迷宫城堡
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 17299 Accepted Submission(s): 7583
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结束。
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
解题思路: 首先声明 本题有坑 不是所有的点与至少一点连通 就是有点不跟任何点相连
wa了十多次我就想不通我这算法哪里写错了 后来加个标记数组就过去了 很迷!
基本思路就是利用Tarjan算法求这个图有多少个强连通分量 算法流程我写在注释里了
import java.util.ArrayList; import java.util.Scanner; import java.util.Stack; public class Main { private static int n; private static int m; private static int[] dfn; private static int[] low; private static int time; private static Stack<Integer> stack; private static int sum; private static ArrayList[] list; private static int[] instack; private static int[] vit; public static void main(String[] args) { // TODO 自动生成的方法存根 Scanner scanner = new Scanner(System.in); while (scanner.hasNext()) { scn(scanner);//输入 bud(); //算法 out(); //输出 } } private static void out() { // TODO 自动生成的方法存根 if (sum==1) { System.out.println("Yes"); }else { System.out.println("No"); } } private static void bud() { dfn = new int [n+1];//次序数组 low = new int [n+1];//记录此点所能到达最早栈中的值 time = 0;//时间戳 sum = 0;//记录此图有几个强连通分量 stack = new Stack<Integer>(); instack = new int [n+1];//记录是否在栈中 vit = new int [n+1]; //强连通分量一定是个环 此栈相当于这个环中的任意一条弧 int h = 0; for (int i = 1; i <=n; i++) { if (vit[i]==0) { vit[i] = 1; h ++; if (h>=2) { sum = 2;break; } Tarjan_bfs(i); } } //假设为连通分量则结构是一个环 //那么 环中任意位置 性质相同 所以起点任意 不影响最终结果 } private static void Tarjan_bfs(int i) { dfn[i] = low[i] = ++time;//low先初始跟次序相同 stack.push(i);//将点i压入栈 instack[i] = 1;//入栈标记 //之后进行bfs搜索 枚举每一种成环的可能 for (int j = 0; j <list[i].size() ; j++) { int k= (int) list[i].get(j); if(vit[k]==0){ vit[k] = 1; Tarjan_bfs(k); low[i] = Math.min(low[i], low[k]); //如果进行了递归存在下一个连通点并且这点不在栈里 //那么根据low的定义 low = min{low[i],low[k]} }else if(instack[k]==1){ low[i] = Math.min(low[i], dfn[k]); //不进行递归那么表示下一个连通点在栈中 //根据low的的定义 low = min{low[i],dnf[k]} } } if (low[i]==dfn[i]) { //当low[i]=dfn[i]表示他自身构成了环 所以他是一个独立的连通分量 sum ++;int k ; //为什么循环出栈呢 //如果所有的点都相互连通那么在最后搜到的点low【最后】=low【首先】 //同理 每当你找到一个强连通分量那么请都弹出去 do { k = stack.pop(); instack[k] = 0; } while (i!=k&&!stack.isEmpty()); } } private static void scn(Scanner scanner) { n = scanner.nextInt(); m = scanner.nextInt(); if(n==0&&m==0){java.lang.System.exit(0);} list = new ArrayList[n+1]; for(int i=0;i<=n;i++){list[i]=new ArrayList<Integer>();} for (int i = 0; i <m; i++) { int a = scanner.nextInt(); int b = scanner.nextInt(); list[a].add(b); } } }