【模板】割点(割顶)

题目背景

割点

题目描述

给出一个n个点,m条边的无向图,求图的割点。

输入输出格式

输入格式:

第一行输入n,m

下面m行每行输入x,y表示x到y有一条边

输出格式:

第一行输出割点个数

第二行按照节点编号从小到大输出节点,用空格隔开

输入输出样例

输入样例#1:
6 7
1 2
1 3
1 4
2 5
3 5
4 5
5 6
输出样例#1:
1 
5

说明

n,m均为100000

tarjan 图不一定联通!!!

思路

dfs求割点;

在DFS搜索树,我们可以发现有两类节点可以成为割点:

  1. 对根节点u,若其有两棵或两棵以上的子树,则该根结点u为割点;
  2. 对非叶子节点u(非根节点),若其子树的节点均没有指向u的祖先节点的回边,说明删除u之后,根结点与u的子树的节点不再连通;则节点u为割点。

2即n->v边中low[v]>=dfn[u];

代码实现

 1 #include<cstdio>
 2 #include<algorithm>
 3 using namespace std;
 4 const int maxn=3e5;
 5 inline int min_(int x,int y){return x<y?x:y;}
 6 int n,m;
 7 int a,b;
 8 int h[maxn],hs,et[maxn],en[maxn];
 9 void add(int u,int v){
10     ++hs,et[hs]=v,en[hs]=h[u],h[u]=hs;
11     ++hs,et[hs]=u,en[hs]=h[v],h[v]=hs;
12 }
13 int s[maxn],ss;
14 int dfn[maxn],dfns,low[maxn],v[maxn];
15 void tarjan(int k,int f){
16     dfn[k]=low[k]=++dfns;
17     for(int i=h[k];i;i=en[i])
18     if(et[i]!=f){
19         if(dfn[et[i]]){
20             low[k]=min_(low[k],dfn[et[i]]);
21         }
22         else{
23             tarjan(et[i],k);
24             low[k]=min_(low[k],low[et[i]]);
25             if(low[et[i]]>=dfn[k]) ++v[k];
26         }
27     }
28     if(f&&v[k]) s[++ss]=k;
29     if(!f&&v[k]>1) s[++ss]=k;
30 }
31 int main(){
32     scanf("%d%d",&n,&m);
33     for(int i=1;i<=m;i++){
34         scanf("%d%d",&a,&b);
35         add(a,b);
36     }
37     for(int i=1;i<=n;i++){
38         if(!dfn[i]){
39             dfns=0;
40             tarjan(i,0);
41         }
42     }
43     sort(s+1,s+ss+1);
44     printf("%d
",ss);
45     for(int i=1;i<=ss;i++) printf("%d ",s[i]);
46     putchar('
');
47     return 0;
48 }

感谢;

http://www.cnblogs.com/en-heng/p/4002658.html

助我一A;

原文地址:https://www.cnblogs.com/J-william/p/7044352.html