zoukankan      html  css  js  c++  java
  • hdu 1269 迷宫城堡(Targin算法)

    ---恢复内容开始---

    迷宫城堡

    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++;
    	}
    }
    

      

      

     

    ---恢复内容结束---

  • 相关阅读:
    听说高手都用记事本写C语言代码?真的假的!
    面向监狱编程,就靠它了!日子是越来越有判头了!
    如何把安静的程序员逼成话唠!
    想要自学编程?一个B站远远不够!
    2021年,学习C++还香吗?(文末赠书)!
    JVM--分代收集理论和垃圾收集算法
    Redis面试题
    基于RT1052 Aworks 使能GPIO输入功能(六)
    基于RT1052 Aworks 使能GPIO输出功能(五)
    基于RT1052 Aworks 使能ADC功能(四)
  • 原文地址:https://www.cnblogs.com/liyinggang/p/5043717.html
Copyright © 2011-2022 走看看