luogu P3388 【模板】割点(割顶)

题目背景

割点

题目描述

给出一个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 图不一定联通!!!

#include<cstdio>
#include<algorithm>
using namespace std;
inline int read() {
    int x=0,f=1;
    char c=getchar();
    while(c<'0'||c>'9') {
        if(c=='-')f=-1;
        c=getchar();
    }
    while(c<='9'&&c>='0') {
        x=x*10+c-'0';
        c=getchar();
    }
    return x*f;
}
const int maxn = 100007;
int low[maxn],dfn[maxn],head[maxn];
struct node{
    int v,next;
}edge[maxn*2];int num,tn;
bool iscut[maxn];
inline void add_edge(int u,int v) {
    edge[++num].v=v;edge[num].next=head[u];head[u]=num;
}
int ans=0;
void tarjan(int u,int fa) { 
    low[u] = dfn[u] = ++tn;
    int cnt_son = 0;
    for (int i=head[u]; i; i=edge[i].next) {
        int v = edge[i].v;
        if (!dfn[v]) {
            cnt_son++;
            tarjan(v,u);
            low[u]=min(low[u],low[v]);
            if (low[v]>=dfn[u])
                if(!iscut[u])
                iscut[u]=true,ans++;
        }
        else if(dfn[v]<dfn[u]&&v!=fa) 
            low[u]=min(low[u],dfn[v]);
    }
    if(fa<0&&cnt_son==1) iscut[u]=false,ans--;
}
int main() {
    //while(1){};
    int n=read(),m=read();
    for(int a,b,i=1;i<=m;++i) {
        a=read(),b=read();
        add_edge(a,b);
        add_edge(b,a);
    }
    for(int i=1;i<=n;++i)
        if(!dfn[i])tarjan(i,-1);
    printf("%d\n",ans);
    int qq=0;
    for(int i=1;i<=n;++i) {
        if(iscut[i])printf("%d ",i);
    }
    return 0;
}

 

posted @ 2017-11-26 06:44  zzzzx  阅读(207)  评论(0编辑  收藏  举报