POJ 2762 Going from u to v or from v to u?(半连通图)

 

题目大意

 

给你一个 n(0<n<1001) 个节点 m(m<6000) 条边的有向图,对于图中的任意两个节点 u 和 v,问能否从 u 走到 v 或者从 v 走到 u

PS:这其实是《算法导论》中讲“强连通分量”的最后一道习题

 

做法分析

 

由于强连通分量重的点肯定能够满足题目的要求,所以可以先将图“化简”,变成 DAG(Directed Acyclic Graph)

 

首先:如果当前的 DAG 有不止一个入读为 0 的点,那么这些点之间肯定不能相互到达,还要明确的是,当前的 DAG 中至少有一个节点的入读为 0(如果没有节点的入读为 0,这些节点肯定能够形成环,和 DAG 中的 Acyclic 矛盾,前面的缩点工作做的就不彻底)

也就是说,现在我们要考虑的就是只有一个点的入读为 0 的情况,这个入读为 0 的点肯定能够到达图中所有的点!

然后我们将这个入读为 0 的点删掉,考虑剩下的 DAG,由于我们只需要考虑两个点之间是否可以从一个点到达另一个点,那么,当前我们要考虑的就是当前的 DAG 中,入读为 0 的点是否只有一个就行了!(还是一样的道理,如果有两个以上的点,这些点之间是不可到达的)

 

于是思路清晰了:

        向将原图缩点,形成 DAG(重新建图是必须的啦)

        对新建好的图拓扑排序:

                每次判断当前是否只有一个点的入读为 0,如果不止一个,跳出拓扑排序过程,输出 No

                将那个入读为 0 的点从新图中删掉,再进行下一轮判断

                如果当前的 DAG 中只剩一个节点,跳出拓扑排序过程,输出 Yes

缩点当然用 Tarjan 了

 

参考代码

POJ 2762
 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <vector>
 5 #include <stack>
 6 
 7 using namespace std;
 8 
 9 const int N=1006;
10 
11 vector <int> arc[N], adj[N];
12 int n, m, t, T, ind;
13 int dfn[N], low[N], id[N], in[N];
14 bool vs[N];
15 stack <int> s;
16 
17 void tarjan(int u)
18 {
19     vs[u]=1, s.push(u);
20     dfn[u]=low[u]=T++;
21     int len=(int)arc[u].size();
22     for(int i=0; i<len; i++)
23     {
24         int v=arc[u][i];
25         if(dfn[v]==-1)
26         {
27             tarjan(v);
28             if(low[u]>low[v]) low[u]=low[v];
29         }
30         else if(vs[v] && low[u]>dfn[v]) low[u]=dfn[v];
31     }
32     if(low[u]==dfn[u])
33     {
34         for(int v; 1; )
35         {
36             v=s.top();
37             s.pop(), vs[v]=0;
38             id[v]=ind;
39             if(v==u) break;
40         }
41         ind++;
42     }
43 }
44 
45 int main()
46 {
47     scanf("%d", &t);
48     for(int ca=1; ca<=t; ca++)
49     {
50         scanf("%d%d", &n, &m);
51         for(int i=0; i<=n; i++) dfn[i]=-1, vs[i]=0, arc[i].clear();
52         while(!s.empty()) s.pop();
53         for(int i=0, a, b; i<m; i++)
54         {
55             scanf("%d%d", &a, &b);
56             arc[a].push_back(b);
57         }
58         ind=T=0;
59         for(int i=1; i<=n; i++) if(dfn[i]==-1) tarjan(i);
60         for(int i=0; i<ind; i++) adj[i].clear(), in[i]=0, vs[i]=0;
61         for(int i=1; i<=n; i++)
62         {
63             int len=(int)arc[i].size(), u=id[i];
64             for(int j=0; j<len; j++)
65             {
66                 int v=id[arc[i][j]];
67                 if(u!=v) adj[u].push_back(v), in[v]++;
68             }
69         }
70         int tot=ind, flag=1;
71         while(flag && tot>1)
72         {
73             int p=-1, cnt=0;
74             for(int i=0; i<ind; i++)
75                 if(!vs[i] && in[i]==0) p=i, cnt++;
76             if(cnt!=1)
77             {
78                 flag=0;
79                 break;
80             }
81             int len=(int)adj[p].size();
82             for(int i=0; i<len; i++) in[adj[p][i]]--;
83             tot--, vs[p]=1;
84         }
85         if(flag) printf("Yes\n"); else printf("No\n");
86     }
87     return 0;
88 }

AC通道

POJ 2762 Going from u to v or from v to u?

原文地址:https://www.cnblogs.com/zhj5chengfeng/p/2962635.html