洛谷P3388 割点数量计算

/**
洛谷3388 计算割点的数量及割点
割点:拆点后图不连通的点 根:child>=2 非: low[v]>=dfn[u];
割桥:割点出度方向所连的边;一般用pair进行存储;
*/

#include<iostream>
#include<algorithm>
#include<vector>
#include<cstdio>
#include<cstring>
#define ll long long
using namespace std;

const int maxn=1e5+7;

int top,bcnt,dcnt;
int sta[maxn],dfn[maxn],low[maxn],belong[maxn];
bool ins[maxn];
int out[maxn];
int u,v,n,m;

std::vector<int> G[maxn];
std::vector<int> GG[maxn];

int parent[maxn];//节点关系;
int iscut[maxn];//当前节点是否为割点;
int cut_num;//割点数量;

void dfs(int u){
    dfn[u]=low[u]=++dcnt;
    ins[u]=true;
    sta[top++]=u;
    int child=0;
    for(int v:G[u]){
        if(dfn[v]==0) {
            child++;
            parent[v]=u;
            dfs(v);
            low[u]=min(low[u],low[v]);
            if((!iscut[u]&&parent[u]!=-1&&low[v]>=dfn[u])||(parent[u]==-1&&child>=2&&!iscut[u])) iscut[u]=1,cut_num++;
            //非根节点low[v]>=dfn[u];当前节点为根节点 且出度为2
        }
        else if(ins[v]) low[u]=min(low[u],dfn[v]);
    }

    /*******************************缩点操作部分 栈记录可能构成强联通分量的点**************/
    if(dfn[u]==low[u]) {
        ++bcnt;
        int pos;
        do{
            pos=sta[--top];
            ins[pos]=false;
            belong[pos]=bcnt;
        }while(pos!=u);
    }
    return ;
}

void tarjan(){
    bcnt=top=dcnt=cut_num=0;
    memset(dfn,0,sizeof(dfn));
    memset(ins,0,sizeof(ins));
    memset(out,0,sizeof(out));
    memset(iscut,0,sizeof(iscut));
    memset(parent,-1,sizeof(parent));
    for(int i=1;i<=n;i++) if(dfn[i]==0) dfs(i);

    /***缩点后图变为GG操作*********************************/
    for(int i=1;i<=n;i++) GG[i].clear();
    for(int i=1;i<=n;i++){
        for(int pos:G[i]){
            int u=belong[i];
            int v=belong[pos];
            if(u!=v) GG[u].push_back(v),++out[u];
        }
    }
}

int main () {
    scanf("%d %d",&n,&m);
    for(int i=1;i<=m;i++){
        scanf("%d %d",&u,&v);
        G[u].push_back(v);
        G[v].push_back(u);
    }
    tarjan();
    printf("%d\n",cut_num);//割点的数量;
    for(int i=1;i<=n;i++) {
        if(iscut[i]){
            cut_num--;
            printf(cut_num==0?"%d\n":"%d ",i);
        }
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值