---恢复内容开始---
迷宫城堡
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Swwubmission(s): 10884 Accepted Submission(s): 4878
Problem Description
为了训练小希的方向感,Gardon建立了一座大城堡,里面有N个房间(N<=10000)和M条通道(M<=100000),每个通道都是单向的,就是说若称某通道连通了A房间和B房间,只说明可以通过这个通道由A房间到达B房间,但并不说明通过它可以由B房间到达A房间。Gardon需要请你写个程序确认一下是否任意两个房间都是相互连通的,即:对于任意的i和j,至少存在一条路径可以从房间i到房间j,也存在一条路径可以从房间j到房间i。
Input
输入包含多组数据,输入的第一行有两个数:N和M,接下来的M行每行有两个数a和b,表示了一条通道可以从A房间来到B房间。文件最后以两个0结束。ww
Output
对于输入的每组数据,如果任意两个房间都是相互连接的,输出"Yes",否则输出"No"。
Sample Input
3 3 1 2 2 3 3 1 3 3 1 2 2 3 3 2 0 0
Sample Output
Yes No
Author
Gardon
Source
强连通算法Targin算法的模板题,不过第一次研究这个算法,牛人啊,写出来这个算法我还要理解半天,,,,
贴几个基本概念:
1.强连通图。在一个强连通图中,任意两个点都通过一定路径互相连通.
2.强连通分量。在一个非强连通图中极大的强连通子图就是该图的强连通分量。(所以说一个强连通图的强连通分量肯定为1,因为他的极大的强连通子图就是自身)
这个算法看似是深搜,但是加了好几个东西DFN数组,LOW数组,栈什么的。。我还要好好去理解下,以免下次碰到类似的题模板都写不出。。
import java.util.Scanner; import java.util.Stack; public class Targin { static class Edge{ //邻接表 int v; int next; //int weight; 这里不需要 } static int[] first;// first[]头结点数组 static int tot; static int n,m; //节点数,边数 static Edge[] edge; //边 static Stack<Integer> S; static boolean[] inStack; static int []DFN; //DFN[]为深搜次序数组(标记时间) static int []low; //Low[u]为u结点或者u的子树结点所能追溯到的最早栈中结点的次序号 static int Count,cnt; //Count记录强连通分量 static int []Belong;//Belong[]为每个结点所对应的强连通分量标号数组 public static void main(String[] args) { Scanner sc = new Scanner(System.in); while(sc.hasNext()){ n = sc.nextInt(); m = sc.nextInt(); if(n==0&&m==0) break; init(); int u,v; for(int i=0;i<m;i++){ u = sc.nextInt(); v= sc.nextInt(); addEdge(u,v); } printGraph(); int cnt=0; for(int i=1;i<=n;i++){ if(DFN[i]==0){ Targin(i); } } //System.out.println(Count); if(Count>1) System.out.println("No"); else System.out.println("Yes"); } } private static void printGraph() { for(int i=1;i<=n;i++){ System.out.print(i); for(int e = first[i];e!=-1;e=edge[e].next){ System.out.print("->"); System.out.print(edge[e].v); } System.out.println(); } } private static void Targin(int u) { DFN[u] = low[u] = ++cnt; inStack[u] = true; S.add(u); //枚举边 for(int e = first[u];e!=-1;e=edge[e].next){ int v = edge[e].v; if(DFN[v]==0){ //j没被访问过 Targin(v); // 更新结点u所能到达的最小次数层 if(low[u]>low[v]) low[u]=low[v]; }else if(inStack[v]&&low[u]>DFN[v]){//如果v结点在栈内 low[u] = DFN[v]; } } if(DFN[u]==low[u]){ //如果节点u是强连通分量的根 Count++; int v; do{ v = S.pop(); Belong[v] = Count; inStack[v] = false; }while(u!=v); } } private static void init() { tot = 0; Count = 0; cnt =0; S = new Stack<Integer>(); edge = new Edge[m+1]; first = new int [n+1]; for(int i=1;i<=n;i++){ first[i] = -1; } Belong = new int [n+1]; DFN = new int [n+1]; low = new int[n+1]; inStack = new boolean[n+1]; } private static void addEdge(int u, int v) { //构建邻接表 edge[tot] = new Edge(); edge[tot].v = v; edge[tot].next = first[u]; first[u] = tot++; } }
---恢复内容结束---