tarjan

TARJAN算法

我先介绍一下这个算法是来干啥的:
它的用处是求强连通分量。 那么,强连通分量又是啥??

在一个有向图中,
强连通:如果两个顶点可以相互通达,则称两个顶点 强连通(strongly connected)
如果有向图G的每两个顶点都 强连通,称G是一个强连通图。非 强连通图有向图的极大强连通 子图,称为强连通分量(strongly connected components)。

算法思路:

第一点,对象图不一定是一个连通图。所以,为了判断每个点是否连通,我们引入一个时间戳。如果他==0则深搜搜他!!

我们还要定义一个变量:low[ ]:该子树中,且仍在栈中的最小时间戳,像是确立了一个关系,low[ ]相等的点在同一强连通分量中。

然后对于搜到的点寻找与其有边相连的点,判断这些点是否已经被搜索过,若没有,则进行搜索。若该点已经入栈,说明形成了环,.则更新low

在不断深搜的过程中如果没有路可走了(出边遍历完了),那么就进行回溯,回溯时不断比较low[ ],去最小的low值。如果dfn[x]==low[x]则x可以看作是某一强连通分量子树的根,也说明找到了一个强连通分量,然后对栈进行弹出操作,直到x被弹出。

算法模板:

#include<cstdio>
#include<cstring>
using namespace std;
const int N=1005;
int x,y,n,id,t,flag,test;
int dfn[N],head[N],block[N],low[N];
struct Node{
	int v,next;
}e[N*N];
int max(int A,int B) {return A>B? A:B;} 
int min(int A,int B) {return A>B? B:A;}
void add(int u,int v) {e[id].v=v;e[id].next=head[u];head[u]=id++;}
#define to e[i].v
void tj(int u)
{
	dfn[u]=low[u]=++t;
	for (int i=head[u];i;i=e[i].next)
	if (!dfn[to]) 
	{
		tj(to);
		low[u]=min(low[u],low[to]);
		if (low[to]>=dfn[u]) ++block[u];
	}
	else low[u]=min(low[u],dfn[to]);
}
 
int main(){
	while(1){
		scanf("%d",&x);
		if (x==0) break;
		memset(e,0,sizeof(e));
		memset(dfn,0,sizeof(dfn));
		memset(low,0,sizeof(low));
		memset(head,0,sizeof(head));
		id=1;t=flag=n=0;
		scanf("%d",&y);add(x,y);add(y,x);n=max(n,x);n=max(n,y);
		whille(1){
			int u,v;
			scanf("%d",&u);
			if (u==0) break;
			scanf("%d",&v);
			add(u,v);add(v,u);
			n=max(n,u);n=max(n,v);
		}
		for (int i=1;i<=n;i++) block[i]=1;block[1]=0;
		tj(1);
		printf("Network #%d\n",++test);
		for(int i=1;i<=n;i++)
		   if(block[i]>1){
			           printf("  SPF node %d leaves %d subnets\n",i,block[i]);
			           flag=1;
		      }
	       if(!flag)printf("  No SPF nodes\n");
        printf("\n");	
	}
	return 0;
}

感谢https://blog.csdn.net/yklcy_1334/article/details/54563832!!!

posted @ 2019-08-04 14:19  HATU  阅读(100)  评论(0编辑  收藏  举报