【图论补完计划】poj 2762 (强连通分量 kosaraju)
Going from u to v or from v to u?
Time Limit: 2000MS | Memory Limit: 65536K | |
Total Submissions: 17479 | Accepted: 4694 |
Description
In order to make their sons brave, Jiajia and Wind take them to a big cave. The cave has n rooms, and one-way corridors connecting some rooms. Each time, Wind choose two rooms x and y, and ask one of their little sons go from one to the other. The son can either go from x to y, or from y to x. Wind promised that her tasks are all possible, but she actually doesn't know how to decide if a task is possible. To make her life easier, Jiajia decided to choose a cave in which every pair of rooms is a possible task. Given a cave, can you tell Jiajia whether Wind can randomly choose two rooms without worrying about anything?
Input
The first line contains a single integer T, the number of test cases. And followed T cases.
The first line for each case contains two integers n, m(0 < n < 1001,m < 6000), the number of rooms and corridors in the cave. The next m lines each contains two integers u and v, indicating that there is a corridor connecting room u and room v directly.
The first line for each case contains two integers n, m(0 < n < 1001,m < 6000), the number of rooms and corridors in the cave. The next m lines each contains two integers u and v, indicating that there is a corridor connecting room u and room v directly.
Output
The output should contain T lines. Write 'Yes' if the cave has the property stated above, or 'No' otherwise.
Sample Input
1 3 3 1 2 2 3 3 1
Sample Output
Yes
题意
询问一个有向图的任意两点s,t,是否存在s可达t或t可达s,如果都存在输出Yes,否则输出No。
做法
scc拆点,建图,记录入度,如果存在两个及两个以上的入度为0的点则无解,找到入度为0的点作为根进行dfs,因为是一条链,如果出现分叉点(新图的点的邻接边数目>=2)则无解。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <vector> 5 #include <algorithm> 6 7 using namespace std; 8 9 const int maxn=1005; 10 11 vector<int> G[maxn]; 12 vector<int> rG[maxn]; 13 vector<int> nG[maxn]; 14 vector<int> vs; 15 16 int n,m; 17 18 int cmp[maxn],d[maxn]; 19 bool used[maxn],tag; 20 21 inline int read(){ 22 int x=0,f=1;char ch=getchar(); 23 while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();} 24 while(ch<='9'&&ch>='0'){x=x*10+ch-'0';ch=getchar();} 25 return x*f; 26 } 27 28 void init(){ 29 for(int i=0;i<maxn;i++){ 30 G[i].clear();rG[i].clear();nG[i].clear(); 31 d[i]=0;cmp[i]=0; 32 } 33 tag=false; 34 } 35 36 void add_edge(int s,int t){ 37 G[s].push_back(t); 38 rG[t].push_back(s); 39 } 40 41 void dfs(int s){ 42 used[s]=true; 43 for(int i=0;i<G[s].size();i++){ 44 if(!used[G[s][i]]) dfs(G[s][i]); 45 } 46 vs.push_back(s); 47 } 48 49 void rdfs(int s,int k){ 50 used[s]=true; 51 cmp[s]=k; 52 for(int i=0;i<rG[s].size();i++){ 53 if(!used[rG[s][i]]) rdfs(rG[s][i],k); 54 } 55 } 56 57 void ndfs(int root){ 58 if(nG[root].size()>1){ 59 tag=true; 60 return; 61 } 62 if(nG[root].size()==0) return; 63 ndfs(nG[root][0]); 64 } 65 66 int scc(){ 67 memset(used,0,sizeof(used)); 68 vs.clear(); 69 for(int i=1;i<=n;i++){ 70 if(!used[i]) dfs(i); 71 } 72 memset(used,0,sizeof(used)); 73 int k=0; 74 for(int i=vs.size()-1;i>=0;i--){ 75 if(!used[vs[i]]) rdfs(vs[i],++k); 76 } 77 return k; 78 } 79 80 int main(){ 81 int T; 82 T=read(); 83 while(T--){ 84 init(); 85 n=read();m=read(); 86 for(int i=0;i<m;i++){ 87 int s,t; 88 s=read();t=read(); 89 add_edge(s,t); 90 } 91 int k=scc(); 92 for(int i=1;i<=n;i++){ 93 for(int j=0;j<G[i].size();j++){ 94 int v=G[i][j]; 95 if(cmp[i]==cmp[v]) continue; 96 nG[cmp[i]].push_back(cmp[v]); 97 d[cmp[v]]++; 98 } 99 } 100 int root=0;bool flag=false; 101 for(int i=1;i<=k;i++){ 102 if(d[i]==0){ 103 if(root){ 104 flag=true; 105 break; 106 } 107 root=i; 108 } 109 } 110 if(flag){ 111 printf("No\n"); 112 } 113 else{ 114 ndfs(root); 115 if(!tag) printf("Yes\n"); 116 else printf("No\n"); 117 } 118 } 119 return 0; 120 }