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

  • 题解:注意不是连通图。。。
  • 代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
#include <set>
#include <map>
using namespace std;
const int maxn=100005;
int n,m,cnt=0;
int indexx;
int root;
int ans[maxn];
int flag[maxn];
vector<int> e[maxn<<1|1];
int low[maxn],num[maxn];
void dfs(int cur,int father){
    int child=0;
    indexx++;
    low[cur]=indexx;
    num[cur]=indexx;
    for(int i=0;i<e[cur].size();i++){
        int u=e[cur][i];
        if(u){
            if(!num[u]){
                child++;
                dfs(u,cur);
                low[cur]=min(low[cur],low[u]);
                if(cur!=root&&low[u]>=num[cur]){
                    flag[cur]=1;
                }
                if(cur==root&&child>=2){
                    flag[u]=1;
                }
            }else if(u!=father){
                low[cur]=min(low[cur],num[u]);
            }
        }
    }
}
int main()
{
    int x,y;
    scanf("%d %d",&n,&m);
    for(int i=0;i<m;i++){
        scanf("%d %d",&x,&y);
        e[x].push_back(y);
        e[y].push_back(x);
    }
    memset(flag,0,sizeof flag);
    memset(num,0,sizeof num);
    memset(low,0,sizeof low);
    root=1,cnt=0;
    for(int i=1;i<=n;i++){
        root=i;
        if(!num[i])
            dfs(i,root);
    }
    int j=0;
    for(int i=1;i<=n;i++){
        if(flag[i]){
            cnt++;
            ans[j++]=i;
        }
    }
    printf("%d
",cnt);
    if(ans[0]) printf("%d",ans[0]);//这里有三个测试点,当割点个数为0的时候后面就不要输出了
    for(int i=1;i<j;i++){
        printf(" %d",ans[i]);
    }
    //printf("
");
    return 0;
}

原文地址:https://www.cnblogs.com/kzbin/p/9205220.html