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: 12692 Accepted: 3271

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


分析:原图中有m条单向边,求任意给两个点,是否能使其中一个点到达另一个点(弱连通)

先用强连通缩点,将在同一个强连通分量里的缩成一个点;

然后建立新图,此时图中只有单向边(即若有u到v,则不会有v到u);

最后利用拓扑,验证新图是否是单链(极端情况只有一个点,但不影响

#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
const int N=1002;
int dfn[N],low[N],belong[N],cnt[N],in[N],out[N],stack[N];
//dfn 深度优先搜索访问次序
//low 能追溯到的最早的次序
//belong 所属强连通分量
//cnt 各个强连通分量所含节点数(本题可不用)
//in 新图节点入度数
//out 新图节点入度数(本题可不用)
//stack 栈模拟数组
int scc,index,top,n,ci,co;
//scc 强连通分量数
//index 索引号
//top 模拟栈顶
//n 原图节点总数
//ci 新图入度为0的节点总数(本题可不用)
//co 新图出度为0的节点总数(本题可不用)
bool instack[N];
//instack 标记是否在栈内
vector<int> g1[N],g2[N];
//g1 原图;g2 新图
int min(int a,int b){return a<b?a:b;}
void init(){
	scc=index=top=0;
	memset(dfn,-1,sizeof(dfn));
	memset(instack,0,sizeof(instack));
	memset(cnt,0,sizeof(cnt));
	for(int i=0;i<=n;i++)g1[i].clear(),g2[i].clear();
}
void tarjan(int x){
	int i,v;
	dfn[x]=low[x]=++index;//为节点x设定次序编号和low初值
	stack[++top]=x,instack[x]=1;//将节点x压入栈中
	for(i=0;i<g1[x].size();i++){ //枚举每一条边
		v=g1[x][i];
		if(dfn[v]==-1){//如果节点v未被访问过
			tarjan(v);//继续向下找
			low[x]=min(low[x],low[v]);
		}else if(instack[v]){//如果节点v还在栈内
			low[x]=min(low[x],dfn[v]);
		}
	}
	if(low[x]==dfn[x]){//如果节点x是强连通分量的根
		scc++;
		while(1){
			v=stack[top--],instack[v]=0;
			belong[v]=scc;
			cnt[scc]++;
			if(v==x)break;
		}
	}
}
void CreateMap(){//建立新图
	int i,j,S,u,v;
	memset(in,0,sizeof(in));
	memset(out,0,sizeof(out));
	for(i=1;i<=n;i++){
		S=g1[i].size();
		for(j=0;j<S;j++){
			u=belong[i],v=belong[g1[i][j]];
			if(u!=v)in[v]++,out[u]++,g2[u].push_back(v);
		}
	}
	ci=co=0;
	for(i=1;i<=scc;i++){
		if(!in[i])ci++;
		if(!out[i])co++;
	}
}
bool TopSort(){//拓扑
	int i,S,u,v;
	top=0;
	for(i=1;i<=scc;i++)if(in[i]==0)stack[++top]=i;
	while(top){
		if(top>1)return 0;
		u=stack[top--];
		S=g2[u].size();
		for(i=0;i<S;i++){
			v=g2[u][i];
			if((--in[v])==0)stack[++top]=v;
		}
	}
	return 1;
}
int main(){
	int T,i,m,a,b;
	scanf("%d",&T);
	while(T--){
		scanf("%d%d",&n,&m);
		init();
		while(m--){
			scanf("%d%d",&a,&b);
			g1[a].push_back(b);
		}
		for(i=1;i<=n;i++)if(dfn[i]==-1)tarjan(i);
		CreateMap();
		puts(TopSort()?"Yes":"No");
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值