一、算法描述
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 }