您的位置:首页 > 运维架构

CUGB图论专场2:G - Going from u to v or from v to u?单连通判断(Tarjan+Topsort)

2014-02-19 13:32 387 查看
G - Going from u to v or from v to u?
Time Limit:2000MS Memory Limit:65536KB 64bit IO Format:%I64d
& %I64u
Submit Status

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


题意:给出的图是否可以随意的指定某两点:从u可以到v 或者从v到u。这里注意的是题目给出的是or!!!!不是双向连通的,而单连通!

思路:那么根据题目意思,就可以用Tarjan算法缩点后,重新建图,然后对新图进行拓扑排序,然后拓扑排序后的点与新图所有的结点总数相同,就说明是单连通的,反之……

不过有剪枝:就是如果出度为0的点有多个,那么肯定不能从u到v,或者从v到u,因为出度为0,所以就没有边连接u和v了;如果新建的图只有一个结点,那么直接是对的。

这题也是WA了好多发,昨天下午做到CF开始都没对,代码都已经早就写好了,改了5个小时都没对,后面晚上回来改也不对,今天做了H题,然后也是一直错,后面单步调试才发现在Tarjan中把min写成了max,靠!!!!!!!!!!!!!!!!!!!!!!细节决定成败啊!!!!!!!!!!做了整整两天了!!!!!

#include <iostream>
#include <cstdio>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <deque>
#include <vector>
#include <list>
#include <queue>
#include <string>
#include <cstring>
#include <map>
#include <stack>
#include <set>
#define PI acos(-1.0)
#define mem(a,b) memset(a,b,sizeof(a))
#define sca(a) scanf("%d",&a)
#define pri(a) printf("%d\n",a)
#define MM 10002
#define MN 1005
#define INF 168430090
using namespace std;
typedef long long ll;
int n,m,cnt,tem,Count,DFN[MN],LOW[MN],id[MN],vis[MN],suo[MN],q2[MN],Map[MN][MN];
stack<int>p;
vector<int>q[MN],q1[MN];
void tarjan(int u)
{
    int j,v;
    DFN[u]=LOW[u]=++cnt;
    vis[u]=1; q2[++tem]=u;
    for(j=0;j<q[u].size();j++)
    {
        v=q[u][j];
        if(!DFN[v])
        {
            tarjan(v);
            LOW[u]=min(LOW[u],LOW[v]); //和H题一样也是把min写成max,所以一直错都不知道,H题的Tarjan算法是从这里拿过去的,所以那题改过来了才知道这题也是这里错,改过来再提交直接AC,唉……昨晚搞到1点都不知道是这里错,大意了!
        }
        else if(vis[v]&&DFN[v]<LOW[u])
            LOW[u]=DFN[v];
    }
    if(DFN[u]==LOW[u])
    {
        Count++;
        do
        {
            v=q2[tem--];
            vis[v]=0;
            suo[v]=Count;
        }while(v!=u);
    }
}
void solve()
{
    Count=cnt=tem=0;
    mem(DFN,0);
    for(int i=1;i<=n;i++)
        if(!DFN[i]) tarjan(i);
}
int topsort()
{
    if(Count==1||n==1) return 1; //如果新建的图只有一个结点,或者原图只有一条边,那肯定对啦
    int i,v,u,sum=0;
    for(i=1;i<=Count;i++)
        if(!id[i]) p.push(i);
    while(!p.empty())
    {
        if(p.size()>1) return 0;  //出度超过2个结点肯定不对
        u=p.top(); p.pop(); sum++;
        for(v=0;v<q1[u].size();v++)
            if(--id[q1[u][v]]==0) p.push(q1[u][v]);
    }
    if(sum!=Count) return 0;
    return 1;
}
void suodian()
{
    for(int i=1;i<=n;i++)
        for(int j=0;j<q[i].size();j++)
            if(suo[q[i][j]]!=suo[i]&&!Map[suo[q[i][j]]][suo[i]])
            {
                id[suo[q[i][j]]]++;
                q1[suo[i]].push_back(suo[q[i][j]]);
                Map[suo[q[i][j]]][suo[i]]=1;
            }
}
void init()
{
    for(int i=0;i<=n;i++)
    {
        q[i].clear();
        q1[i].clear();
    }
    while(!p.empty()) p.pop();
    mem(vis,0); mem(suo,0); mem(id,0); mem(Map,0);
}
int main()
{
    int t,u,v;
    sca(t);
    while(t--)
    {
        init(); //多case需要初始化
        scanf("%d%d",&n,&m);
        while(m--)
        {
            scanf("%d%d",&u,&v);
            q[u].push_back(v);
        }
        solve();
        suodian();
        if(topsort()) puts("Yes");
        else puts("No");
    }
    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: