CSP201509-4(高速公路)(Java 90分)

版权声明:本文为博主原创文章,转载请注明出处 https://blog.csdn.net/qq_24681499/article/details/83213334

问题描述
  某国有n个城市,为了使得城市间的交通更便利,该国国王打算在城市之间修一些高速公路,由于经费限制,国王打算第一阶段先在部分城市之间修一些单向的高速公路。
  现在,大臣们帮国王拟了一个修高速公路的计划。看了计划后,国王发现,有些城市之间可以通过高速公路直接(不经过其他城市)或间接(经过一个或多个其他城市)到达,而有的却不能。如果城市A可以通过高速公路到达城市B,而且城市B也可以通过高速公路到达城市A,则这两个城市被称为便利城市对。
  国王想知道,在大臣们给他的计划中,有多少个便利城市对。
输入格式
  输入的第一行包含两个整数n, m,分别表示城市和单向高速公路的数量。
  接下来m行,每行两个整数a, b,表示城市a有一条单向的高速公路连向城市b。
输出格式
  输出一行,包含一个整数,表示便利城市对的数量。
样例输入
5 5
1 2
2 3
3 4
4 2
3 5
样例输出
3
样例说明
在这里插入图片描述
思路:这个题题意很明显,就是求强连通分量,对于任意一个顶点数大于等于2的 强连通分量,假设强连通分量内的顶点数为n,那么该强连通分量共有n*(n-1)/2个遍历城市对。所以重点就是求强连通分量。我用了Kosaraju算法。
求强连通分量的有名算法一共有两个 Tarjan 和 Kosaraju。
Kosaraju 容易理解,但算法时间复杂度较高,容易爆内存
Tarjan 难理解,但是算法时间复杂度低,相比于 Kosaraju不容易爆内存
关于这两个算法的详细解释请移步 https://www.cnblogs.com/reddest/p/5932153.html
我的Java代码90分,原因是爆内存了。
这是我的提交记录在这里插入图片描述
第一次提交时得了90分,提示运行错误
然后我找原因,没找到,继续提交,一模一样的代码居然变成80分了。
我又试了一次还是80分。。
然后我把

G[i]=new ArrayList<>();
rG[i]=new ArrayList<>();

改成了

G[i]=new ArrayList<>(n);
rG[i]=new ArrayList<>(n);

提交以后变成0分了。。
所以总结出来就是爆内存了。。

接下来贴我的代码:

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
public class D {
	static int V;//顶点数
	static List<Integer> G[];//图的邻接表示
	static List<Integer> rG[];//把边反向后的图
	static List<Integer> vs;//后序遍历的顶点序列
	static boolean used[];//访问标记
	static int cmp[];//所属强连通分量的拓扑序
	static Map<Integer, Integer> map;//每个强联通分量的顶点个数
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt();
		int m =sc.nextInt();
		V = n;
		G =new ArrayList[n];
		rG = new ArrayList[n];
		for(int i=0;i<n;i++) {
			G[i]=new ArrayList<>();
			rG[i]=new ArrayList<>();
		}
		vs =new ArrayList<>();
		used  = new boolean[n];
		cmp = new int[n];
		map = new HashMap<Integer, Integer>();
		
		for(int i=0;i<m;i++) {
			add_edge(sc.nextInt()-1, sc.nextInt()-1);
		}
		int tmp = scc();
		int result=0;
		for(int i=0;i<tmp;i++) {
			int t1 = map.get(i);
			if(t1>=2) {
				int t2=t1*(t1-1)/2;
				result+=t2;
			}
		}
		System.out.println(result);
		
	}
	static void add_edge(int from,int to) {
		G[from].add(to);
		rG[to].add(from);
	}
	static void dfs(int v) {
		used[v] = true;
		for(int i=0;i<G[v].size();i++) {
			if(!used[G[v].get(i)]) {
				dfs(G[v].get(i));
			}
		}
		vs.add(v);
	}
	static void rdfs(int v,int k) {
		used[v] = true;
		
		cmp[v]=k;
		for(int i=0;i<rG[v].size();i++) {
			if(!used[rG[v].get(i)]) {
				rdfs(rG[v].get(i),k);
			}
		}
	}
	public static int scc() {
		for(int i=0;i<used.length;i++) {
			used[i]=false;
		}
		for(int i=0;i<V;i++) {
			if(!used[i]) {
				dfs(i);
			}
		}
		for(int i=0;i<used.length;i++) {
			used[i]=false;
		}
		int k=0;
		for(int i=vs.size()-1;i>=0;i--) {
			if(!used[vs.get(i)]) {
				rdfs(vs.get(i),k);
				k++;
			}
		}
		for(int i=0;i<V;i++) {
			if(map.containsKey(cmp[i])) {
				map.put(cmp[i], map.get(cmp[i])+1);
			}
			else {
				map.put(cmp[i],1);
			}
		}
		return k;
	}
}

等有时间我会尝试用Tarjan 算法重做一遍。
如有错误,欢迎指正。

猜你喜欢

转载自blog.csdn.net/qq_24681499/article/details/83213334
今日推荐