POJ 2762 Going from u to v or ... 弱连通图 tarjan

题意:就是判断一个图是否为弱连通图。

思路:先用tarjan处理一遍找出强连通分量。然后将每个强连通分量缩点,形成一个有向无环图。

如果该有向无环图是一个无分叉的树的话,即是弱连通图。

如果有分叉,则分叉两端的节点无法互相到达,即不是弱连通图。


#include<iostream>
#define min(a,b) (a<b?a:b)
using namespace std;
const int N=1005,M=6005;
int n,m;
int edgehead[N];
struct Edge
{
	int v,next;
}edge[M];
int indegree[N];
int outdegree[N];
bool instack[N];
int dfn[N],low[N];
int k=1;
void addedge(int u,int v)
{
	edge[k].v=v;
	edge[k].next=edgehead[u];
	edgehead[u]=k++;
}
int stack[N];
int sp=0;
int index=0;
int headsta[N];
int ph=0;
int father[N];
void tarjan(int i)
{
	dfn[i]=low[i]=++index;
	instack[i]=true;
	stack[sp++]=i;
	for(int j=edgehead[i];j;j=edge[j].next)
	{
		int v=edge[j].v;
		if(!dfn[v])
		{
			tarjan(v);
			low[i]=min(low[i],low[v]);
		}
		else if(instack[v])
		{
			low[i]=min(low[i],dfn[v]);
		}
	}
	if(dfn[i]==low[i])
	{
		headsta[ph++]=i;
		int ans;
		do
		{
			ans=stack[--sp];
			father[ans]=i;
			instack[ans]=false;

		}while(ans!=i);
	}
}
bool vis[N];
int sum;
bool dfs(int root,int w)
{
	if(w==sum)
		return true;
	for(int i=edgehead[root];i;i=edge[i].next)
	{
		int v=edge[i].v;
		if(father[v]!=father[root]&&!vis[v])
		{
			vis[v]=true;
			return dfs(v,w+1);
		}
	}
	return false;
}
void solve()
{
	for(int i=1;i<=n;i++)
	{
		if(!dfn[i])
			tarjan(i);
	}
	for(int i=1;i<=n;i++)
	{
		for(int j=edgehead[i];j;j=edge[j].next)
		{
			if(father[edge[j].v]!=father[i])
			{
				indegree[father[edge[j].v]]++;
				outdegree[father[i]]++;
			}
		}
	}
	sum=ph;
	while(ph>0)
	{
		int now=headsta[--ph];
		if(indegree[now]==0)
		{
			vis[now]=true;
			if(dfs(now,1))
				printf("Yes\n");
			else
				printf("No\n");
			break;
		}
	}
}
int main()
{	int cases;
	scanf("%d",&cases);
	while(cases--)
	{
		k=1;
		memset(vis,0,sizeof(vis));
		memset(dfn,0,sizeof(dfn));
		memset(low,0,sizeof(low));
		memset(edge,0,sizeof(edge));
		memset(edgehead,0,sizeof(edgehead));
		memset(instack,0,sizeof(instack));
		memset(headsta,0,sizeof(headsta));
		memset(indegree,0,sizeof(indegree));
		memset(outdegree,0,sizeof(outdegree));
		memset(father,0,sizeof(father));
		sp=0;
		ph=0;
		index=0;
		scanf("%d%d",&n,&m);
		for(int i=1;i<=m;i++)
		{
			int from,to;
			scanf("%d%d",&from,&to);
			addedge(from,to);
		}
		solve();
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值