您的位置:首页 > 其它

【模板】割点(割顶)

2017-06-18 15:07 225 查看

题目背景

割点

题目描述

给出一个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搜索树,我们可以发现有两类节点可以成为割点:

对根节点u,若其有两棵或两棵以上的子树,则该根结点u为割点;

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

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

代码实现

#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=3e5;
inline int min_(int x,int y){return x<y?x:y;}
int n,m;
int a,b;
int h[maxn],hs,et[maxn],en[maxn];
void add(int u,int v){
++hs,et[hs]=v,en[hs]=h[u],h[u]=hs;
++hs,et[hs]=u,en[hs]=h[v],h[v]=hs;
}
int s[maxn],ss;
int dfn[maxn],dfns,low[maxn],v[maxn];
void tarjan(int k,int f){
dfn[k]=low[k]=++dfns;
for(int i=h[k];i;i=en[i])
if(et[i]!=f){
if(dfn[et[i]]){
low[k]=min_(low[k],dfn[et[i]]);
}
else{
tarjan(et[i],k);
low[k]=min_(low[k],low[et[i]]);
if(low[et[i]]>=dfn[k]) ++v[k];
}
}
if(f&&v[k]) s[++ss]=k;
if(!f&&v[k]>1) s[++ss]=k;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
scanf("%d%d",&a,&b);
add(a,b);
}
for(int i=1;i<=n;i++){
if(!dfn[i]){
dfns=0;
tarjan(i,0);
}
}
sort(s+1,s+ss+1);
printf("%d\n",ss);
for(int i=1;i<=ss;i++) printf("%d ",s[i]);
putchar('\n');
return 0;
}


感谢;
http://www.cnblogs.com/en-heng/p/4002658.html
助我一A;
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: