模板——tarjan求割点

在一个无向图中,如果有一个顶点集合,删除这个顶点集合以及这个集合中所有顶点相关联的边以后,图的连通分量增多,就称这个点集为割点集合。

注意求割点中的low定义:

割点中low[u]记录节点u或u的子树通过非父子边追溯到最早的祖先节点(即DFS次序号最小)

当(u,v)为树边且low[v] >= dfn[u]时,节点u才为割点。该式子的含义:以节点v为根的子树所能追溯到最早的祖先节点要么为v要么为u。

根节点需要特判,若图不保证联通,要搜索多次

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const int N=200005;
 5 
 6 vector<int> v[20005];
 7 int n,m;
 8 int dfn[N],low[N],cnt=0,vis[N],bl[N],tot=0;
 9 
10 void dfs(int u,int f)
11 {
12     int ch=0;
13     dfn[u]=++cnt;
14     low[u]=cnt;
15     vis[u]=1;
16     for(int i=0;i<(int)v[u].size();i++)
17     {
18         int p=v[u][i];
19         if(vis[p]) 
20         {
21             if(p!=f) low[u]=min(low[u],dfn[p]);
22             //因为搜到u的点f必定肯定dfn最为接近于dfn[u],故dfn[p]<dfn[f],所以只需赋值成dfn[p] 
23             //搜索顺序一定是p->f->u,若f>p,则应是p搜到u(按照dfs顺序) 
24             //强连通就需要 low[u]=min(low[u],low[p]);
25         }
26         else
27         {
28             ch++;
29             dfs(p,u);
30             low[u]=min(low[u],low[p]);
31             if(f==-1&&ch>=2) bl[u]=1;
32             if(f!=-1&&low[p]>=dfn[u]) bl[u]=1;
33         }
34     }
35 }
36 
37 int main()
38 {
39     scanf("%d%d",&n,&m);
40     for(int i=1;i<=m;i++)
41     {
42         int x,y;
43         scanf("%d%d",&x,&y);
44         v[x].push_back(y);
45         v[y].push_back(x);
46     }
47     for(int i=1;i<=n;i++)
48     {
49         if(!vis[i]) dfs(i,-1);//不一定是连通图 
50     }
51     for(int i=1;i<=n;i++) tot+=bl[i];
52     cout<<tot<<endl;
53     for(int i=1;i<=n;i++) if(bl[i]) printf("%d ",i);
54 }
View Code

猜你喜欢

转载自www.cnblogs.com/Forever-666/p/10799272.html
今日推荐