Going from u to v or from v to u?
Time Limit: 2000MS | Memory Limit: 65536K | |
Total Submissions: 12804 | Accepted: 3311 |
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
题意:给出一个有向图,判断该图是否为单向连通图:如果有向图中,对于任意节点v1和v2,至少存在从v1到v2和从v2到v1的路径中的一条,则原图为单向连通图。
思路:先对原图进行缩点。可以证明,若是单向连通图,缩点后形成的图形是一棵树,入度为0的点是这颗树的根,这棵树只能是单链,不能有分叉,因为如果有分叉,则这些分叉之间是不可达的。所以我们缩点后对新图进行拓扑排序,若拓扑排序的过程中,删除一个点和对应的边后,有超过1个点的入度为0,则该图不是单向连通图。
AC代码:
#include <iostream> #include <cstdio> #include <cstring> #include <string> #include <algorithm> #include <queue> #include <vector> #include <cmath> #include <cstdlib> #include <map> #define L(rt) (rt<<1) #define R(rt) (rt<<1|1) #define ll long long using namespace std; const int maxn=1005; const int maxm=6005; const double INF=1000000000; struct node { int v,next; }edge[maxm*2]; int G[maxn],NG[maxn],scc[maxn],in[maxn]; int low[maxn],dfn[maxn],stack[maxn]; bool ins[maxn]; int n,m,num,cnt,snum,top; void init() { memset(G,-1,sizeof(G)); memset(NG,-1,sizeof(NG)); num=0; } void add(int *head,int u,int v) { edge[num].v=v; edge[num].next=head[u]; head[u]=num++; } void input() { int a,b; scanf("%d%d",&n,&m); while(m--) { scanf("%d%d",&a,&b); add(G,a,b); } } void dfs(int u) { int x; dfn[u]=low[u]=++cnt; stack[top++]=u; ins[u]=true; for(int i=G[u];i!=-1;i=edge[i].next) { int v=edge[i].v; if(!dfn[v]) { dfs(v); low[u]=min(low[u],low[v]); } else if(ins[v]) low[u]=min(low[u],dfn[v]); } if(low[u]==dfn[u]) { snum++; do{ x=stack[--top]; ins[x]=false; scc[x]=snum; }while(x!=u); } } void tarjan() { memset(ins,false,sizeof(ins)); memset(dfn,0,sizeof(dfn)); snum=top=cnt=0; for(int i=1;i<=n;i++) if(!dfn[i]) dfs(i); } bool toposort() { queue<int>Q; for(int u=1;u<=snum;u++) if(!in[u]) Q.push(u); while(!Q.empty()) { if(Q.size()>1) return false; int u=Q.front(); Q.pop(); for(int i=NG[u];i!=-1;i=edge[i].next) { int v=edge[i].v; in[v]--; if(!in[v]) Q.push(v); } } return true; } void solve() { memset(in,0,sizeof(in)); for(int u=1;u<=n;u++) for(int i=G[u];i!=-1;i=edge[i].next) { int v=edge[i].v; if(scc[u]!=scc[v]) { add(NG,scc[u],scc[v]); in[scc[v]]++; } } if(toposort()) printf("Yes\n"); else printf("No\n"); } int main() { int t; scanf("%d",&t); while(t--) { init(); input(); tarjan(); solve(); } return 0; }