Going from u to v or from v to u?
Time Limit: 2000MS | Memory Limit: 65536K | |
Total Submissions: 19520 | Accepted: 5256 |
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
题意:
给你n个点,m条边,问这个图能否达到以下条件,随意从1~n中任意选择两个点x和y,总是存在一条路可以从x走到y或者从y走到x;
做法:
如果题意中把或者改成并且的话,这道题就是一道强连通分量水题,只要判断是不是全图是一个强连通就好了,但是因为是胡或者,所以我们应该先再强连通缩点,在没有环的情况下进行考虑,如果在没有环之后留下来的是一条链,则永远可以从一个点到达另一个点,这样我们就要用拓扑排序来考虑,而且因为必须是一条链(如果是树形的话,子树之间就不能相互走到了),所以拓扑排序的时候每次队列中只能有一个点。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<stack>
#include<vector>
#include<queue>
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
const int maxn=100050;
int n,m,head[maxn],now;
int belong[maxn],qiang,dfn[maxn],low[maxn],cnt;
int in[maxn];
stack<int> sa;
vector<int> ve[maxn];
struct node{
int from,to,next;
}e[50005];
void add(int u,int v){
e[now].from=u;e[now].to=v;
e[now].next=head[u],head[u]=now++;
}
void tarjan(int x){
dfn[x]=low[x]=++cnt;
sa.push(x);
for(int i=head[x];~i;i=e[i].next){
int v=e[i].to;
if(!dfn[v]){
tarjan(v);
low[x]=min(low[x],low[v]);
}
else if(!belong[v]) low[x]=min(low[x],low[v]);
}
if(dfn[x]==low[x]){
qiang++;
while(1){
int u=sa.top();sa.pop();
belong[u]=qiang;
if(u==x) break;
}
}
}
int topo(){
int flag=0;
queue<int> q;
for(int i=1;i<=qiang;i++){
if(!in[i]) q.push(i);
}
while(!q.empty()&&!flag){
int u=q.front();q.pop();
if(!q.empty()) flag=1;
for(int i=0;i<ve[u].size();i++){
int t=ve[u][i];
if(--in[t]==0){
q.push(t);
}
}
}
return !flag;
}
void init(){
mem(head,-1); mem(low,0);
mem(dfn,0); mem(belong,0);
mem(in,0); qiang=cnt=now=0;
for(int i=0;i<=1001;i++)
ve[i].clear();
while(!sa.empty()) sa.pop();
}
int main(){
int t,x,y;
cin>>t;
while(t--){
scanf("%d%d",&n,&m);
init();
for(int i=0;i<m;i++){
scanf("%d%d",&x,&y);
add(x,y);
}
for(int i=1;i<=n;i++)
if(!dfn[i]) tarjan(i);
for(int i=0;i<now;i++){
int fx=belong[e[i].from],fy=belong[e[i].to];
if(fx!=fy){
ve[fx].push_back(fy);
in[fy]++;
}
}
int ans=topo();
if(ans) printf("Yes\n");
else printf("No\n");
}
return 0;
}