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

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.

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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值