首页 > 代码库 > 【模板】割点(割顶)

【模板】割点(割顶)

题目背景

割点

题目描述

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

输入输出格式

输入格式:

第一行输入n,m

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

输出格式:

第一行输出割点个数

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

输入输出样例

输入样例#1:
6 71 21 31 42 53 54 55 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\n",ss);45     for(int i=1;i<=ss;i++) printf("%d ",s[i]);46     putchar(\n);47     return 0;48 }

感谢;

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

助我一A;

【模板】割点(割顶)