poj 2762 Going from u to v or from v to u?(缩点+拓扑排序)

来源:互联网 发布:淘宝专业盗图 编辑:程序博客网 时间:2024/06/05 06:34
Going from u to v or from v to u?
Time Limit: 2000MS Memory Limit: 65536KTotal 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.

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
题意:给出一个有向图,判断该图是否为单向连通图:如果有向图中,对于任意节点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 longusing 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;}


原创粉丝点击