欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

洛谷 P3388 【模板】割点(割顶)(Tarjan)

程序员文章站 2022-04-28 15:27:16
题目链接 https://www.luogu.org/problemnew/show/P3388 模板题 解题思路 什么是割点? 怎样求割点? dfn :即时间戳,一张图的dfs序(dfs遍历时出现的顺序) 树边:连向孩子的边 反向边:连向祖先的边 low :即一个点能到达的时间戳最小的边(反向边只 ......

题目链接

https://www.luogu.org/problemnew/show/p3388

模板题


 

解题思路

什么是割点?

怎样求割点?

  • dfn :即时间戳,一张图的dfs序(dfs遍历时出现的顺序)
  • 树边:连向孩子的边
  • 反向边:连向祖先的边
  • low :即一个点能到达的时间戳最小的边(反向边只能经过一条)

显然,一个点如果它的任意一个孩子的low大于等于这个点,那么这个点就是割点。

ac代码

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<set>
 5 #include<stack>
 6 using namespace std;
 7 const int maxn=20005;
 8 const int maxm=200005;
 9 int n,m,cnt,dfn[maxn],low[maxn],times,p[maxn];
10 bool iscut[maxn];
11 struct edge{
12     int u;
13     int v;
14     int next;
15 }e[maxm];
16 stack<edge> s;
17 void insert(int u,int v){
18     ++cnt;
19     e[cnt].u=u;
20     e[cnt].v=v;
21     e[cnt].next=p[u];
22     p[u]=cnt;
23 }
24 void dfs(int u,int fa){
25     dfn[u]=low[u]=++times;
26     int child=0;
27     for(int i=p[u];i!=-1;i=e[i].next){
28         int v=e[i].v;
29         if(dfn[v]==0){
30             child++;
31             dfs(v,u);
32             low[u]=min(low[u],low[v]);
33             if(low[v]>=dfn[u])iscut[u]=true;
34         }
35         else if(dfn[v]<dfn[u]&&v!=fa){
36             low[u]=min(low[u],dfn[v]);
37         }
38     }
39     if(fa==-1&&child==1) iscut[u]=false;
40 }
41 int main()
42 {
43     cin>>n>>m;
44     memset(p,-1,sizeof(p));
45     memset(low,0x3f3f3f,sizeof(low));
46     for(int i=1;i<=m;i++){
47         int x,y;
48         scanf("%d%d",&x,&y);
49         insert(x,y);
50         insert(y,x);
51     }
52     for(int i=1;i<=n;i++){
53         if(!dfn[i]) dfs(i,-1);
54     }
55     int ans=0;
56     for(int i=1;i<=n;i++){
57         if(iscut[i]) ans++;
58     }
59     cout<<ans<<endl;
60     for(int i=1;i<=n;i++){
61         if(iscut[i]) cout<<i<<" ";
62     }
63     return 0;
64 }