图的单向连通
poj 2762
题意:任给一个图,问你对于任意的两个点x,y之间是否存在从x到y或从y到x的路径?
分析:这显然是要求图是否为单向连通图?我们可以对强连通分量进行缩点,缩点后的图一定是一个有向无环图; 现在,问题等价于给你一个有向无环图,问你它是否为单向连通图。这样,我们就可以对有向无环图进行拓扑排序,当且仅当得到的拓扑序列中任意相邻两点间边连通,即topo[i]--topo[i+1]之间存在边时,有向无环图是单向连通图。
1 #include<cstdio> 2 #include<cstring> 3 #include<queue> 4 #include<algorithm> 5 #define _Clr(x, y) memset(x, y, sizeof(x)) 6 #define INF 0x3f3f3f3f 7 #define N 1010 8 using namespace std; 9 10 struct Node 11 { 12 int to, next; 13 }edge[N*6]; 14 int head[N], tot; 15 int dfn[N], low[N]; 16 int bleg[N], Sta[N]; 17 bool instack[N]; 18 int cnt, top, ght, n; 19 20 void Init() 21 { 22 cnt=tot=ght=top=0; 23 _Clr(head, -1); 24 _Clr(dfn, 0); 25 _Clr(instack, 0); 26 } 27 28 void Add_edge(int a, int b) 29 { 30 edge[tot].to = b; 31 edge[tot].next = head[a]; 32 head[a] = tot++; 33 } 34 35 void dfs(int u) 36 { 37 dfn[u]=low[u]=++cnt; 38 Sta[top++] = u; 39 instack[u] = true; 40 for(int i=head[u]; i!=-1; i=edge[i].next) 41 { 42 int v = edge[i].to; 43 if(!dfn[v]) 44 { 45 dfs(v); 46 low[u] = min(low[u], low[v]); 47 } 48 else if(instack[v]) low[u] = min(low[u], dfn[v]); 49 } 50 if(low[u]==dfn[u]) 51 { 52 ght++; 53 // printf("Num: %d\n",ght); 54 int v; 55 do 56 { 57 v = Sta[--top]; 58 // printf("%d ", v); 59 instack[v] = false; 60 bleg[v] = ght; 61 }while(u!=v); 62 // puts(""); 63 } 64 } 65 66 int inde[N], mat[N][N]; 67 void Tarjan() 68 { 69 for(int i=1; i<=n; i++) 70 if(!dfn[i]) dfs(i); 71 72 _Clr(inde, 0); 73 _Clr(mat, 0); 74 // 缩点建立新的有向无环图并且求每个点的入度 75 for(int u=1; u<=n; u++) 76 for(int i=head[u]; i!=-1; i=edge[i].next) 77 { 78 int v = edge[i].to; 79 if(bleg[v] != bleg[u]) 80 { 81 inde[bleg[v]]++; 82 mat[bleg[u]][bleg[v]] = 1; 83 } 84 } 85 } 86 87 int topo[N], k=0; 88 void TopSort() 89 { 90 queue<int> Q; 91 for(int i=1; i<=ght; i++) 92 if(inde[i]==0) Q.push(i); 93 // printf("TopSort: \n"); 94 k=0; 95 while(!Q.empty()) 96 { 97 int u = Q.front(); Q.pop(); 98 // printf("%d ", u); 99 topo[++k] = u; 100 for(int i=1; i<=ght; i++) 101 { 102 if(!mat[u][i]) continue; 103 inde[i]--; 104 if(inde[i]==0) Q.push(i); 105 } 106 } 107 // puts(""); 108 } 109 110 void Solved() 111 { 112 bool tag = true; 113 // printf("k=%d\n", k); 114 for(int i=1; i<k; i++) 115 if(!mat[topo[i]][topo[i+1]]) //若拓扑序列存在两个相邻的点之间不连通则非单向连通图 116 { 117 tag = false; 118 break; 119 } 120 puts(tag ? "Yes" : "No"); 121 } 122 123 int main() 124 { 125 int T, m, a, b; 126 scanf("%d", &T); 127 while(T--) 128 { 129 Init(); 130 scanf("%d%d", &n, &m); 131 while(m--) 132 { 133 scanf("%d%d",&a, &b); 134 Add_edge(a, b); 135 } 136 Tarjan(); 137 TopSort(); 138 Solved(); 139 } 140 return 0; 141 }