一、算法描述
Tarjan算法求割点仍然用了tarjan思想中dfs求prenum的dfs序号,parent的dfs树,以及lowest这样一个记录最早回溯位置的数组。lowest计算时求下列情况的最小值,即:
lowest[u]的值为:prenum[u];如果存在一条非树边(u,v),使得u与一个树上顶点连通,这种情况下的prenum[v];u的所有子节点的lowest
tarjan处理完成后根据下列标准计算割点:
1. 如果DFS树根节点的子节点≥2,那么根节点是一个割点(充要条件)
2. 对于各顶点u,令p=parent[u],如果prenum[p]≤lowest[u],那么p是一个割点(此处注意,p是割点而不是u是割点,如果p是根节点那么按1计算)
二、代码
tarjan预处理:
1 int order=0;
2 int dfs_tarjan(int now,int last){
3 prenum[now]=++order;
4 parent[now]=last;
5 lowest[now]=min(lowest[now],prenum[now]);
6 vis[now]=true;
7 for(int i=0;i<a[now].size();i++){
8 int to=a[now][i];
9 if(del[to])
10 continue;
11 if(vis[to]){
12 if(parent[now]!=to)
13 lowest[now]=min(lowest[now],prenum[to]);
14 }
15 else lowest[now]=min(lowest[now],dfs_tarjan(to,now));
16 }
17 return lowest[now];
18 }
统计割点数量:
1 order=0;
2 for(int j=1;j<=n;j++){
3 vis[j]=false;
4 lowest[j]=INT_MAX;
5 }
6 int now=1;
7 while(del[now])
8 now+=1;
9 dfs_tarjan(now,now);
10 int cnt=0;
11 for(int j=1;j<=n;j++){
12 if(del[j])
13 continue;
14 if(parent[j]==now&&j!=now)
15 cnt+=1;
16 }
17 if(cnt>=2)
18 res+=1;
19 for(int j=1;j<=n;j++){
20 if(del[j])
21 continue;
22 int p=parent[j];
23 if(p==now)
24 continue;
25 if(prenum[p]<=lowest[j])
26 res+=1;
27 }