hdu1269--求强连通分量个数--tarjan--图的静态邻接表

#include<stdio.h>
#include<string.h>
#include<stack>
using namespace std;
stack<int>s;
int ret;
struct node
{
	int v,next;
} e[100010];
int ins[10010],fang[10010],head[10010],low[10010];
int n,m,yong;
void tarjan(int k)
{
	int j,u;
	fang[k]=low[k]=yong++;
	ins[k]=1;
	s.push(k);//强连通为什么要用栈?栈中其往上的都是可能和他是同一连通分量的,不可以访问非栈上节点是他们不可能在同一连通分量上(访问过而不在栈上,还可能是同一连通分量么),若访问 访问过而不在栈上 的节点(不是同一连通分量,他们早已出栈,说明他们的根还是比较高的,对他没有更新)
	for(j=head[k];j;j=e[j].next)
	{
		u=e[j].v;
		if(fang[u]==0)
		{
			tarjan(u);
			if(low[u]<low[k])
				low[k]=low[u];
		}else if(ins[u]&&fang[u]<low[k])//u可能在上一路上已被访问过,或者u就是k的祖先,他们一定是同一连通分量;与双连通不同的是:他要求的是自己不越过自己,所以,即使他有回边,早晚更新都是一样;双连通担心的是他提前更新,导致他的孩子也提前更新,从而fang[本节点]>low[孩子]=low[本节点]=low[本节点的父节点]
			low[k]=fang[u];
	}
	if(low[k]==fang[k])//其能探到的最低的不越过他自己,说明其以下是一个连通分量
	{
		ret++;
		do{
		j=s.top();
		s.pop();
		ins[j]=0;
		}while(j!=k);
	}
}
int main()
{
	int i,a,b;
	while(1)
	{
		ret=0;
		yong=1;
		scanf("%d%d",&n,&m);
		if(n==0&&m==0)
			break;
		memset(head,0,sizeof(head));
		for(i=1;i<=m;i++)
		{
			scanf("%d%d",&a,&b);
			e[yong].v=b;
			e[yong].next=head[a];
			head[a]=yong;
			yong++;
		}
		yong=1;
		memset(ins,0,sizeof(ins));
		memset(fang,0,sizeof(fang));
		for(i=1;i<=n;i++)
			if(fang[i]==0)
				tarjan(i);
		if(ret==1)
			printf("Yes\n");
		else printf("No\n");
	}
	return 0;
}

你可能感兴趣的:(hdu1269--求强连通分量个数--tarjan--图的静态邻接表)