洛谷3388,tarjan求图的割点

第一次接触求割点,虽然是模板题,但是还是出了些问题,好在AC了,用的是并查集判断是否在同一个连通分量中。

/*************************************************************************
    > File Name: main.cpp
    > Author:Eagles 
    > Mail:None 
    > Created Time: 2018年09月10日 星期一 20时58分47秒
    > Description:LUOGU3388 
 ************************************************************************/

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 100005
struct node
{
    int to;
    int nex;
}E[N*2];
int n,m;
int head[N];
int par[N];
int low[N],dfn[N];
int cnt;
bool cut[N];//判断该点是否是割点
int dep;

int find_par(int x)
{
    return x==par[x]?x:par[x]=find_par(par[x]);
}

void unite(int x, int y)
{
    int fx=find_par(x);
    int fy=find_par(y);
    par[fy]=fx;
}

void addEdge(int a, int b)
{
    E[cnt].to=b;
    E[cnt].nex=head[a];
    head[a]=cnt++;

    E[cnt].to=a;
    E[cnt].nex=head[b];
    head[b]=cnt++;
}

void init()
{
    memset(head,-1,sizeof(head));
    memset(dfn,-1,sizeof(dfn));
    cnt=dep=0;
    for (int i=0; i<n; i++)
        par[i]=i;

    for (int i=0; i<m; i++)
    {
        int a,b;
        scanf("%d%d",&a,&b);
        addEdge(a-1,b-1);
        unite(a-1,b-1);
    }
}

void tarjan(int u, int fa)
{
    low[u]=dfn[u]=dep++;
    int child=0;

    for (int k=head[u]; k!= -1; k=E[k].nex)
    {
        int v=E[k].to;

        if (dfn[v]==-1)
        {
            tarjan(v,u);

            low[u]=min(low[u],low[v]);

            if (u==fa)
                child++;

            if (low[v]>=dfn[u]&&u!=fa)
                cut[u]=true;
        }
        else if (v != fa)
            low[u]=min(low[u],dfn[v]);
    }

    if (child>=2&&u==fa)
        cut[u]=true;

}
void solve()
{
    for (int i=0; i<n; i++)
    {
        if (par[i]==i)
        {
            tarjan(i,i);
        }
    }

    int num=0;

    for (int i=0; i<n ;i++)
        if (cut[i])
            num++;

    printf("%d\n",num);
    for (int i=0; i<n; i++)
        if (cut[i])
            printf("%d ",i+1);
    printf("\n");

}

int main()
{


    while (~scanf("%d%d",&n,&m))
    {
        init();
        solve();
    }
    return 0;
}

路漫漫其修远兮,吾将上下而求索。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值