洛谷3388 割点(割顶)模板

题目背景

割点

题目描述

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

Q

注意:
1.如果root有至少2个孩子,那么root就是割点;
有1个孩子不是;

2.遍历完图后,在回溯时找割点,所以更新放在if(!dfn[x])里面;

#include
#include
#include
#include
using namespace std;
const int MAXN=500010;
int fst[MAXN],nxt[MAXN],low[MAXN],dfn[MAXN],flag[MAXN];
int n,m,root=-1,tot,tim,cnt;
struct hh
{
    int from,to;
}ma[MAXN];
void build(int f,int t)
{
    tot++;
    ma[tot]=(hh){f,t};
    nxt[tot]=fst[f];
    fst[f]=tot;
    return;
}
void dfs(int x,int fa)
{
    int ch=0;
    low[x]=dfn[x]=++tim;
    for(int i=fst[x];i;i=nxt[i])
    {
        int v=ma[i].to;
        if(!dfn[v]) 
        {
            ch++;
            dfs(v,x);
            low[x]=min(low[x],low[v]);
            if((x!=root && low[v]>=dfn[x]) || (x==root && ch>=2))
            {
                if(!flag[x]) cnt++;//一个点可能重复访问;
                flag[x]=1;
            }
        }
        else if(v!=fa) low[x]=min(low[x],dfn[v]);
    }
    return;
}
void solve()
{
    int x,y;
    cin>>n>>m;
    for(int i=1;i<=m;i++) 
    scanf("%d%d",&x,&y),build(x,y),build(y,x);
    for(int i=1;i<=n;i++)
        if(!dfn[i]) root=i,dfs(i,root);
    cout<"\n";
    for(int i=1;i<=n;i++) 
    if(flag[i]) printf("%d ",i);
}
int main()
{
    solve();
    return 0;
}

你可能感兴趣的:(tarjan)