POJ 2762 Going from u to v or from v to u? (强连通分量缩点+拓扑排序)
题目链接:http://poj.org/problem?id=2762
题意是 有t组样例,n个点m条有向边,取任意两个点u和v,问u能不能到v 或者v能不能到u,要是可以就输出Yes,否则输出No。注意一点,条件是或者!所以不是判断双连通图的问题。
我一开始没看到'or'这个条件,所以直接tarjan判断是否只有一个强连通分量,果断WA。
所以需要给原图缩点,用tarjan把图变成一个有向无环图,要是只有一个scc,那就直接输出Yes。那接下来讨论多个scc,要是新图中有两个及以上的点的入度为0,则这些点都不能相互到达,所以输出No,所以我们找到唯一一个入度为0的点作为root,然后从这个点来拓扑排序,出队入队的过程肯定是一进一出的,所以根据过程来判断是否输出Yes和No。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <vector> 5 #include <queue> 6 using namespace std; 7 const int MAXN = 1005; 8 struct data { 9 int next , to; 10 }edge[MAXN * 6]; 11 int head[MAXN] , st[MAXN] , low[MAXN] , dfn[MAXN] , block[MAXN] , du[MAXN]; 12 int top , ord , sccnum , cont; 13 bool instack[MAXN]; 14 vector <int> G[MAXN]; 15 16 inline void add(int u , int v) { 17 edge[cont].next = head[u]; 18 edge[cont].to = v; 19 head[u] = cont++; 20 } 21 22 void init() { 23 memset(head , -1 , sizeof(head)); 24 memset(dfn , 0 , sizeof(dfn)); 25 memset(du , 0 , sizeof(du)); 26 memset(instack , false , sizeof(instack)); 27 top = sccnum = ord = cont = 0; 28 } 29 30 void tarjan(int u) { 31 low[u] = dfn[u] = ++ord; 32 st[++top] = u; 33 instack[u] = true; 34 for(int i = head[u] ; ~i ; i = edge[i].next) { 35 int v = edge[i].to; 36 if(!dfn[v]) { 37 tarjan(v); 38 low[u] = min(low[u] , low[v]); 39 } 40 else if(instack[v]) { 41 low[u] = min(low[u] , low[v]); 42 } 43 } 44 if(low[u] == dfn[u]) { 45 int v; 46 sccnum++; 47 do { 48 v = st[top--]; 49 instack[v] = false; 50 block[v] = sccnum; 51 }while(u != v); 52 } 53 } 54 55 void top_sort() { 56 queue <int> que; 57 while(!que.empty()) { 58 que.pop(); 59 } 60 cont = 0; 61 for(int i = 1 ; i <= sccnum ; i++) { 62 if(!du[i]) { 63 que.push(i); 64 cont++; 65 } 66 } 67 if(cont > 1) { 68 printf("No\n"); 69 return ; 70 } 71 while(!que.empty()) { 72 int temp = que.front() , cnt = 0; 73 que.pop(); 74 for(int i = 0 ; i < G[temp].size() ; i++) { 75 du[G[temp][i]]--; 76 if(!du[G[temp][i]]) { 77 cnt++; 78 cont++; 79 que.push(G[temp][i]); 80 } 81 } 82 if(cnt > 1) { 83 printf("No\n"); 84 return ; 85 } 86 } 87 if(cont != sccnum) { 88 printf("No\n"); 89 } 90 else { 91 printf("Yes\n"); 92 } 93 } 94 95 int main() 96 { 97 int t , n , m , u , v; 98 scanf("%d" , &t); 99 while(t--) { 100 scanf("%d %d" , &n , &m); 101 init(); 102 for(int i = 0 ; i < m ; i++) { 103 scanf("%d %d" , &u , &v); 104 add(u , v); 105 } 106 for(int i = 1 ; i <= n ; i++) { 107 G[i].clear(); 108 if(!dfn[i]) 109 tarjan(i); 110 } 111 if(sccnum == 1) { 112 printf("Yes\n"); 113 continue; 114 } 115 for(int u = 1 ; u <= n ; u++) { 116 for(int i = head[u] ; ~i ; i = edge[i].next) { 117 int v = edge[i].to; 118 if(block[u] != block[v]) { 119 du[block[v]]++; 120 G[block[u]].push_back(block[v]); 121 } 122 } 123 } 124 top_sort(); 125 } 126 }