poj2762 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: 14564 Accepted: 3845

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,可以u到达v或者v到达u,如果可以输出Yes,否则输出No
先求强联通缩点,然后将点进行拓扑排序,如果有分叉,则说明不行,也就是说缩点之后必须是单链。
心得:对着答案终于对出错误来了。 加油!!!
另外,提供三组测试数据
3
3 3
1 2
2 3
3 1
3 3
1 2
2 1
3 1
4 4
1 2
1 3
2 4
3 4
Yes
Yes
No
过了这三组应该能过
Time:2014-10-5 17:33
*/
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
#define MAX 1010
#define mem(a,b) memset(a,b,sizeof(a))
struct Edge{
	int to,next;
}edge[MAX<<3],edge1[MAX<<3];
int en,en1;
int head[MAX],head1[MAX];
int dfn[MAX],in[MAX],low[MAX],id[MAX],stack[MAX];
bool instack[MAX];
int idx,top,cnt;
void Add(int u,int v){
	edge[en].to=v;
	edge[en].next=head[u];
	head[u]=en++;
}
void Add1(int u,int v){
	edge1[en1].to=v;
	edge1[en1].next=head1[u];
	head1[u]=en1++;
}
void Init(){
	cnt=en=en1=idx=top=0;
	mem(dfn,0);mem(low,0);
	mem(id,0);mem(stack,0);
	mem(instack,0);mem(in,0);
	mem(head,-1);mem(head1,-1);
}
void Tarjan(int u){
	dfn[u]=low[u]=++idx;
	stack[++top]=u;instack[u]=true;
	int v;
	for(int i=head[u];i!=-1;i=edge[i].next){
		v=edge[i].to;//i错写成u 
		if(dfn[v]==0){
			Tarjan(v);
			low[u]=min(low[u],low[v]);
		}else if(instack[v]){
			low[u]=min(low[u],dfn[v]);
		}
	}
	if(dfn[u]==low[u]){
		cnt++;
		do{
			v=stack[top--];
			id[v]=cnt;
			instack[v]=false;
		}while(u!=v);
	}
}
bool topSort(){
	queue<int>q;
	for(int i=1;i<=cnt;i++){
		if(in[i]==0)
		q.push(i); 
	}
	if(q.size()>1)return false;
	while(!q.empty()){
		int cur=q.front();q.pop();
		for(int i=head1[cur];i!=-1;i=edge1[i].next){
			int v=edge1[i].to;
			in[v]--;
			if(in[v]==0){
				q.push(v);
			}
		}
		if(q.size()>1) return false;
	}
	return true;
}
void solve(){
	int T,N,M;
	scanf("%d",&T);
	while(T--){
		int u,v;
		Init();
		scanf("%d%d",&N,&M);
		for(int i=0;i<M;i++){
			scanf("%d%d",&u,&v);
			Add(u,v);
		}
		for(int i=1;i<=N;i++){
			if(!dfn[i])//没被访问过 三处错 
			Tarjan(i);
		}
		if(cnt==1){printf("Yes\n");continue;}
		for(int i=1;i<=N;i++){
			for(int j=head[i];j!=-1;j=edge[j].next){
				int v=edge[j].to;//两处错 
				if(id[i]!=id[v]){
					in[id[v]]++;
					Add1(id[i],id[v]);
				}
			}
		}
		if(topSort()){
			printf("Yes\n");
		}else{
			printf("No\n");
		}
	}
}
int main(){
	//freopen("poj2762.txt","r",stdin);
	solve();
return 0;
} 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值