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 }

 

你可能感兴趣的:(POJ 2762 Going from u to v or from v to u? (强连通分量缩点+拓扑排序))