POJ 2762 tarjan缩点+并查集+度数

Going from u to v or from v to u?
Time Limit: 2000MS Memory Limit: 65536K
Total Submissions: 15494 Accepted: 4100

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. 

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

Source

 
题目意思:
给一n个点、m条边的有向图,问是否随意选两个点u和v,是否能从u到达v或者从v到达u。
 
思路:
如果弱连通分量有多个,那么肯定是不可到达的,所以用并查集处理一下。
强连通分量内部随意两个点是互相到达的,不互相到达的点在强连通分量之间,所以先用tarjan强连通分量缩点,若入度为0的个数>=2||出度为0的个数>=2那么也是不可到达的。
各种条件判断一下即可。
 
代码:
  1 #include <cstdio>
  2 #include <cstring>
  3 #include <algorithm>
  4 #include <iostream>
  5 #include <vector>
  6 #include <queue>
  7 #include <cmath>
  8 #include <set>
  9 #include <stack>
 10 using namespace std;
 11 
 12 #define N 1005
 13 
 14 int max(int x,int y){return x>y?x:y;}
 15 int min(int x,int y){return x<y?x:y;}
 16 int abs(int x,int y){return x<0?-x:x;}
 17 
 18 int n, m;
 19 bool in[N];
 20 int suo[N];
 21 int cnt;
 22 vector<int>ve[N];
 23 int dfn[N], low[N], Time;
 24 stack<int>st;
 25 int father[N];
 26 
 27 int findroot(int u){
 28     if(father[u]!=u) father[u]=findroot(father[u]);
 29     return father[u];
 30 }
 31 
 32 void tarjan(int u){
 33     dfn[u]=low[u]=Time++;
 34     st.push(u);in[u]=true;
 35     int i, j, k;
 36     for(i=0;i<ve[u].size();i++){
 37         int v=ve[u][i];
 38         if(dfn[v]==-1){
 39             tarjan(v);
 40             low[u]=min(low[u],low[v]);
 41         }
 42         else if(in[v]) low[u]=min(low[u],dfn[v]);
 43     }
 44     if(dfn[u]==low[u]){
 45         while(1){
 46             int x=st.top();
 47             suo[x]=cnt;
 48             in[x]=false;
 49             st.pop();
 50             if(x==u||st.empty()) break;
 51         }
 52         cnt++;
 53     }
 54 }
 55 
 56 main()
 57 {
 58     int i, j, k, u, v;
 59     int t;
 60     cin>>t;
 61     
 62     while(t--){
 63         scanf("%d %d",&n,&m);
 64         for(i=0;i<=n;i++) ve[i].clear();
 65         for(i=0;i<m;i++){
 66             scanf("%d %d",&u,&v);
 67             ve[u].push_back(v);
 68         }
 69         Time=cnt=1;
 70         memset(dfn,-1,sizeof(dfn));
 71         while(!st.empty()) st.pop();
 72         memset(in,false,sizeof(in));
 73         for(i=1;i<=n;i++){
 74             if(dfn[i]==-1){
 75                 tarjan(i);
 76             }
 77         }
 78         int inn[N], out[N];
 79         memset(inn,0,sizeof(inn));
 80         memset(out,0,sizeof(out));
 81         for(i=1;i<=n;i++) father[i]=i;
 82         for(i=1;i<=n;i++){
 83             for(j=0;j<ve[i].size();j++){
 84                 int u=suo[i], v=suo[ve[i][j]];
 85                 if(u!=v){
 86                     father[findroot(v)]=findroot(u);
 87                     inn[v]++;
 88                     out[u]++;
 89                 }
 90             }
 91         }
 92         
 93         int num=0;
 94         for(i=1;i<cnt;i++){
 95             if(father[i]==i) num++;
 96         }
 97         if(num>1) {
 98             printf("No\n");continue;
 99         }
100     
101         int n1, n2;
102         n1=n2=0;
103         for(i=1;i<cnt;i++){
104             if(!inn[i]) n1++;
105             if(!out[i]) n2++;
106         }
107         if(n1>1||n2>1) printf("No\n");
108         else printf("Yes\n");
109     }
110 }

 

转载于:https://www.cnblogs.com/qq1012662902/p/4637805.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值