今天自学了tarjan求割点的算法。一开始有一些不会的地方,后来问了同学和学长才弄懂。感觉自己好垃圾啊,,
问题:
为什么当
low[v]>=dfn[u]
时,u即为割点?
这样看好像不太懂,但是把等式反过来,
dfn[u]<=low[v]
,因为low[v]是子节点通过非父子边追溯到的最早的祖先节点,dfn[u]为当前节点在dfs过程中被遍历到的次序号,由于子节点通过非父子边追溯不到比u更靠上的祖先节点,则说明u为v向上追溯时的必经节点,则u为一个割点。
程序实现:
(其实n并没有什么卵用)
#include<cstdio>
#include<iostream>
using namespace std;
int n,m,i,x,y,num,counter;
int head[5000];
int fa[5000];
int vis[5000];
int low[5000];
int dfn[5000];
struct aa
{
int next,to;
}a[10000];
void add(int from,int to)
{
a[++num].next=head[from];
a[num].to=to;
head[from]=num;
}
void dfs(int u)
{
int children=0;
vis[u]=1;
low[u]=dfn[u]=++counter;
for(int i=head[u];i;i=a[i].next)
{
int v=a[i].to;
if(!vis[v])
{
children++;
fa[v]=u;
dfs(v);
low[u]=min(low[u],low[v]);
if(!fa[u]&&children>1)
printf("关节点:%d\n",u);
else if(low[v]>=dfn[u])
printf("关节点:%d\n",u);
}
else if(v!=fa[u])
low[u]=min(low[u],dfn[v]);
}
}
main()
{
scanf("%d%d",&n,&m);
for(i=1;i<=m;i++)
{
scanf("%d%d",&x,&y);
add(x,y);add(y,x);
}
dfs(1);
}