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

题目链接

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 }

 

posted @ 2019-05-24 19:59 尹昱钦 阅读(...) 评论(...) 编辑 收藏