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

时间:2023-02-03 20:53:29

G - Going from u to v or from v to u?
Time Limit:2000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u

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