云里雾里学Tarjan(强连通分量)

首先让我先来说一说关于强连通分量的一些疑惑

1、当我已经知道了我要走的下一步节点在栈中,我能不能把比较中的DFN写成LOW?

2、如果low[v]>=dfn[u],此时u就是割点,这个东西怎么证明?

这里链接两篇Tarjan算法写的非常好的博客:

1、全网最!详!细!tarjan算法讲解

2、割点(Tarjan算法)

↑洛谷有模板

下面是鄙人写的裸的Tarjan求图中强连通分量的代码!

//Tarjan基本的算法实现 

#include<bits/stdc++.h>
using namespace std;
struct sd{
	int v,next;
}edge[1001];
int DFN[1001],LOW[1001];
int stk[1001],head[1001],vis[1001],cnt,tot,index,n,m;
void add(int x,int y)
{//链式前向星 
	edge[++cnt].next=head[x];
	edge[cnt].v=y;
	head[x]=cnt;return; 
}
void tarjan(int x)
{
	DFN[x]=LOW[x]=++tot;
	stk[++index]=x;
	vis[x]=1;
	for(int i=head[x];i;i=edge[i].next)
	{
		if(!DFN[edge[i].v])
		tarjan(edge[i].v),LOW[x]=min(LOW[x],LOW[edge[i].v]);
		else if(vis[edge[i].v])
		LOW[x]=min(LOW[x],DFN[edge[i].v]);
	}
	if(DFN[x]==LOW[x])
	{
		while(stk[index]!=x)
			printf("%d ",stk[index]),vis[stk[index]]=0,index--;
		printf("%d\n",stk[index]),vis[stk[index]]=0,index--;
	}
} 
int main()
{
	scanf("%d%d",&n,&m);
	int x,y;
	for(int i=1;i<=m;++i)
	{
		scanf("%d%d",&x,&y);
		add(x,y);
	}
	for(int i=1;i<=n;++i)
	{
		if(!DFN[i]) tarjan(i);
	}
	return 0;
} 
/*
6 8
1 2
1 4
2 3
3 6
2 5
5 6
4 5
5 1
*/

下面是我给出的求割点的tarjan算法程序。我还是有一些东西没有搞懂。(带有注释)

这里给一张图方便理解:(红色的是DFN,蓝色的是LOW)

例题:P3388 【模板】割点(割顶)

//tarjan算法求割点,我好像自己也不是很懂
#include<bits/stdc++.h>
using namespace std;
const int N=100010;
struct sd{
	int next,v;
}edge[2*N];
int head[N],DFN[N],LOW[N],cnt=0,tot=0,n,m; 
bool judge[N];
void add(int x,int y)
{
	edge[++cnt].next=head[x];
	edge[cnt].v=y;
	head[x]=cnt;
}
void tarjan(int x,int fa)
{
	int child=0;
	DFN[x]=LOW[x]=++tot;
	for(int i=head[x];i;i=edge[i].next)
	{
		int v=edge[i].v;//v是要到达的点 
		if(!DFN[v])
		{
			tarjan(v,fa);
			LOW[x]=min(LOW[x],LOW[v]);
			if(LOW[v]>=DFN[x]&&x!=fa)judge[x]=true;//就是说明下一个点的最早能追溯到的节点比当前点的dfs序大或等于 
			if(x==fa)child++;//找回来了,说明已经遍历完了一颗子树
		}
		LOW[x]=min(LOW[x],DFN[v]);//?? 判断回边因为是无向图!!!这里不能改的过于大了不能改成LOW否则容易出问题! 
	}
	if(child>=2&&x==fa)judge[x]=true;
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;++i)
	{
		int a,b;
		scanf("%d%d",&a,&b);
		add(a,b);
		add(b,a);
	}
	for(int i=1;i<=n;++i)
	if(!DFN[i])tarjan(i,i);
	int ans=0;
	for(int i=1;i<=n;++i)
	if(judge[i])ans++;printf("%d\n",ans);
	for(int i=1;i<=n;++i)
	if(judge[i])printf("%d ",i);
	return 0;
}

By njc

posted @ 2020-07-17 12:47  Mudrobot  阅读(121)  评论(0编辑  收藏  举报