POJ 2762 Going from u to v …(强连通分量+拓扑排序)

来源:互联网 发布:女明星的淘宝店铺 编辑:程序博客网 时间:2024/04/28 18:08

题意:给你一个有向图,问是否对于任意的X,Y两个顶点,可以从X走到Y,从Y走到X

思路:是或!!!如果没有或字的话那么就是简单的判断一个图是否为强连通。有或字了的话就相当于转化为原图中每一个强连通分量之间是否连通的问题。为什么呢,因为强连通分量内部是肯定可以从X走到Y和Y走到X的了。然后缩点,对缩点形成的图最多只能由一个入度为0的点,如果有多个入度为0的点则它们肯定不连通,缩点形成的图是一棵树,入度为0的点就是这棵树的树根,而且这棵树只能是单链,一旦有分叉,那么分叉点就不满足题目。相当于找一个全序,直接拓扑排序就可以了。


#include <cstdio>#include <queue>#include <cstring>#include <iostream>#include <cstdlib>#include <algorithm>#include <vector>#include <map>#include <string>#include <set>#include <ctime>#include <cmath>#include <cctype>#include <stack>using namespace std;#define maxn 1000+100#define LL long longint cas=1,T;vector<int>G[maxn];vector<int>NewG[maxn];int pre[maxn];int lowlink[maxn];int sccno[maxn];int dfs_clock,scc_cnt;int indegree[maxn];int n,m;stack<int>S;void dfs(int u){pre[u]=lowlink[u]=++dfs_clock;S.push(u);for (int i = 0;i<G[u].size();i++){int v = G[u][i];if (!pre[v]){dfs(v);lowlink[u] = min(lowlink[u],lowlink[v]);}else if (!sccno[v]){lowlink[u] = min (lowlink[u],pre[v]);}}if (lowlink[u] == pre[u]){scc_cnt++;for (;;){int x = S.top();S.pop();sccno[x] = scc_cnt;if (x==u)break;}}}void find_scc(int n){dfs_clock=scc_cnt=0;memset(sccno,0,sizeof(sccno));memset(pre,0,sizeof(pre));for (int i = 1;i<=n;i++)if (!pre[i])dfs(i);}int in[maxn];int out[maxn];bool topo(){queue<int> Q;int sum = 0;for (int i = 1;i<=scc_cnt;i++)if (indegree[i]==0)Q.push(i);while (!Q.empty()){if (Q.size()>1)               //队列里面只有一个元素才能保证是全序return false;int u = Q.front();Q.pop();sum++;for (int i = 0;i<NewG[u].size();i++){int v = NewG[u][i];if (--indegree[v]==0)Q.push(v);}}return sum == scc_cnt;}int main(){//freopen("in","r",stdin);scanf("%d",&T);while (T--){scanf("%d%d",&n,&m);for (int i = 0;i<=n;i++){G[i].clear();            NewG[i].clear();}memset(indegree,0,sizeof(indegree));memset(in,0,sizeof(in));memset(out,0,sizeof(out));for (int i = 1;i<=m;i++){int u,v;scanf("%d%d",&u,&v);G[u].push_back(v);}find_scc(n);for (int i = 1;i<=scc_cnt;i++){            in[i]=out[i]=1;}for (int u = 1;u<=n;u++)for (int i =0;i<G[u].size();i++){int v = G[u][i];if (sccno[u] != sccno[v]){in[sccno[v]]=out[sccno[u]]=0;                    NewG[sccno[u]].push_back(sccno[v]);indegree[sccno[v]]++;}}printf("%s\n",topo()?"Yes":"No");         }return 0;}

题目

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

13 31 22 33 1

Sample Output

Yes


0 0
原创粉丝点击