首页 > 代码库 > POJ 2762判断单联通(强连通缩点+拓扑排序)

POJ 2762判断单联通(强连通缩点+拓扑排序)

Going from u to v or from v to u?
Time Limit: 2000MS Memory Limit: 65536K
Total Submissions: 14789 Accepted: 3915

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

Source

POJ Monthly--2006.02.26,zgl & twb

[Submit]   [Go Back]   [Status]   [Discuss]


题意:对于任意两个节点u,v,如果能从u到v或者v到u,那么输出Yes,否则输出No。

思路:先强连通缩点,此时一定不含环,看能不能找到一条最长路包含所有的缩点就行(实际上是找判断单链),用拓扑排序就ok,不过如果只有一个强连通分量那么一定是Yes啦,否则topo排序判断 ,代码如下

#include<iostream>  
#include<algorithm>  
#include<cstdio>  
#include<queue>
#include<cstring>  
#include<cmath>  
using namespace std;
typedef long long ll;
const int maxn =1e4+10;
const ll mod=20140413;
vector<int>G1[maxn],G2[maxn],G[maxn];
int sccno[maxn],vis[maxn],scc_cnt;//sccno强连通编号,scc_cnt表示强连通分量的个数
int ind[maxn];//ind表示入度
void init_G(int n)//初始化缩点图
{
	memset(ind,0,sizeof ind);
	for(int i=1;i<=n;i++)G[sccno[i]].clear();
	for(int i=1;i<=n;i++) {
		for(int j=0;j<G1[i].size();++j){
			int &v =G1[i][j];
			if(sccno[i]!=sccno[v]) {
				G[sccno[i]].push_back(sccno[v]);
				ind[sccno[v]]++;
			}
		}
	}
}
bool toposort(int n)//topo排序
{
	init_G(n);
	int u,cnt=0;
	queue<int>q;
	for(int i=1;i<=n;i++){
		if(!ind[sccno[i]]){
			if(!q.empty())return false;
			q.push(sccno[i]);
			cnt++;
		}
	}
	while(!q.empty()){
		u=q.front();
		q.pop();
		ind[u]=-1;
		for(int i=0;i<G[u].size();i++) {
			int &v=G[u][i];
			ind[v]--;
			if(ind[v]==0){
				if(!q.empty())return false;
				q.push(v);
				cnt++;
			}
		}
	}
	return cnt==scc_cnt;
}
vector<int>S;
void init(int n)
{
	memset(vis,0,sizeof vis);
	memset(sccno,0,sizeof sccno);
	S.clear();
	scc_cnt=0;
	for(int i=1;i<=n;i++) {
		G1[i].clear();
		G2[i].clear();
		G[i].clear();
	}
}
void AddEdge(int u,int v)
{
	G1[u].push_back(v);
	G2[v].push_back(u);
}
void dfs1(int u)
{
	if(vis[u])return ;
	vis[u]=1;
	for(int i=0;i<G1[u].size();i++)dfs1(G1[u][i]);
	S.push_back(u);
}
void dfs2(int u)
{
	if(sccno[u]) return ; 
	sccno[u]=scc_cnt;
	for(int i=0;i<G2[u].size();++i)dfs2(G2[u][i]);
}
bool is_Semiconnect(int n)///计算强连通分量,初步判断
{
	for(int i=1;i<=n;i++)dfs1(i);
	for(int i=S.size();i>=1;i--){
		if(!sccno[S[i-1]]){
			scc_cnt++;
			dfs2(S[i-1]);
		}
	}
	return scc_cnt<=1;
}
int main()  
{  
   int T,n,m; 
   scanf("%d",&T);
   while(T--) {
   		scanf("%d%d",&n,&m);
   		int u,v;
   		init(n);
   		while(m--) {
   			scanf("%d%d",&u,&v);
   			AddEdge(u,v);
   		}
   		if(is_Semiconnect(n))puts("Yes");
   		else{
   			if(toposort(n))puts("Yes");
   			else puts("No");
   		}
   	}
   return 0;  
}

POJ 2762判断单联通(强连通缩点+拓扑排序)