HDU1269-迷宫城堡-tarjan算法

http://acm.hdu.edu.cn/showproblem.php?pid=1269


View Code
 1 void tarjan(int x) 
 2 { 
 3     int i, a; 
 4     low[x] = dfn[x] = index; // 刚搜到一个节点时low = dfn 
 5     index++; 
 6     stack[++head] = x; // 将该节点入栈  
 7     instack[x] = 1; // 将入栈标记设置为1 
 8     for(i = 1; i <= n; i++) // 遍历入栈节点的边 
 9     { 
10         if(!map[x][i]) // 如果两点之间没有边 
11             continue; // 不用管它 
12         if(dfn[i] == -1) // 如果新搜索到的节点是从未被搜索过 
13         { 
14             tarjan(i); // 那自然就得搜索这个节点 
15             low[x] = min(low[x], low[i]); // 回溯的时候改变当前节点的low值  
16         } 
17         else if(instack[i]) // 如果新搜索到的节点已经被搜索过而且现在在栈中  
18         { 
19             low[x] = min(low[x], dfn[i]); // 更新当前节点的low值,这里的意思是两个节点之间有一条可达边,而前面  
20         }                                 // 而前面节点已经在栈中,那么后面的节点就可能和前面的节点在一个联通分量中  
21     }  
22      
23     if(low[x] == dfn[x]) // 最终退回来的时候 low == dfn , 没有节点能将根节点更新,那  
24     {                   // low == dfn 的节点必然就是根节点 
25         int temp;  
26         while(1) // 一直出栈到此节点, 这些元素是一个强联通分量  
27         { 
28             temp = stack[head--]; // 弹出栈元素  
29             belong[temp] = cnt; // 为了方便计算,将强联通分量进行标记 
30             instack[temp] = 0; // 将栈内标记置为0  
31             if(temp == x)     // 一直弹到x出现为止  
32                 break; 
33         } 
34         cnt++; 
35     }  
36 }                        
37   
38  
39 void solve() 
40 { 
41     int i, j; 
42     int t1, t2; 
43     while(scanf("%d", &n) != EOF) // 
44     { 
45         init(); // 初始化  
46         for(i = 1; i <= n; i++) //   
47             if(dfn[i] == -1) // 如果某点没被访问过,则对其进行tarjan  
48                 tarjan(i);          // tarjan的成果是得到了一个belong数组,记录每个节点分别属于哪个强联通分量  
49         for(i = 1; i <= n; i++) // 遍历每条边,找到缩点之后的边  
50         { 
51             for(j = 1;j <= n; j++) 
52             { 
53                 if(map[i][j] && belong[i] != belong[j]) // 两点之间有边,但不是属于一个强联通分量的边 
54                 { 
55                     out[belong[i]]++; // 缩点后的点入度+1  
56                     in[belong[j]]++;// 缩点后的点出度+1  
57                 }  
58             }        
59         } 
60          
61         t1 = 0, t2 = 0; 
62          
63         for(i = 1; i < cnt; i++) 
64         { 
65             if(in[i] == 0) 
66                 t1++; 
67             if(out[i] == 0) 
68                 t2++; 
69         } 
70         if(cnt == 2) 
71             printf("1\n0\n"); 
72         else 
73             printf("%d\n%d\n", t1, max(t1, t2)); 
74     } 
75 } 
76  

 




#include<iostream> #include<vector> using namespace std; #define Max 10010 //题目中可能的最大点数 int STACK[Max],top=0; //Tarjan 算法中的栈 bool InStack[Max]; //检查是否在栈中 int DFN[Max]; //深度优先搜索访问次序 int Low[Max]; //能追溯到的最早的次序 int ComponentNumber=0; //有向图强连通分量个数 int Index=0; //索引号 vector <int> Edge[Max]; //邻接表表示 vector <int> Component[Max]; //获得强连通分量结果 int InComponent[Max]; //记录每个点在第几号强连通分量里 int ComponentDegree[Max]; //记录每个强连通分量的度 void Tarjan(int i) { int j; DFN[i]=Low[i]=Index++; InStack[i]=true; STACK[++top]=i; for (int e=0; e<Edge[i].size(); e++) { j=Edge[i][e]; if (DFN[j]==-1) { Tarjan(j); Low[i]=min(Low[i],Low[j]); } else if (InStack[j]) Low[i]=min(Low[i],DFN[j]); } if (DFN[i]==Low[i]) { ComponentNumber++; do { j=STACK[top--]; InStack[j]=false; Component[ComponentNumber].push_back(j); InComponent[j]=ComponentNumber; } while (j!=i); //cout<<ComponentNumber<<endl; } } void solve(int N) //N是此图中点的个数,注意是0-indexed! { memset(STACK,-1,sizeof(STACK)); memset(InStack,0,sizeof(InStack)); memset(DFN,-1,sizeof(DFN)); memset(Low,-1,sizeof(Low)); top=0; Index=0; ComponentNumber=0; for(int i=1;i<=N;i++) if(DFN[i]==-1) Tarjan(i); } int main() { int N, M; int a, b; while(cin>>N>>M, N||M) { int i; for(i=0; i<=N+1; i++) { Component[i].clear(); Edge[i].clear(); } for(i=1; i<=M; i++) { scanf("%d%d", &a, &b); Edge[a].push_back(b); } solve(N); if(ComponentNumber == 1) cout<<"Yes\n"; else cout<<"No\n"; } return 0; }

 

posted @ 2013-03-09 16:29  另Ⅰ中Feel▂  阅读(336)  评论(0编辑  收藏  举报