割点——有向图点的双连通分量

求无向图删除一个节点之后还剩下多少连通块(点的双连通分量:极大的不包含割点的连通块)

#include <iostream>
#include <cstring>

using namespace std;

const int N = 10010, M = 30010;

int n, m;
int h[N], e[M], ne[M], idx;
int dfn[N], low[N], timestamp;  //dfn兼判重数组
int root;  // 记录每个连通块的"根节点"
int ans;  // 记录每个连通块去掉一个点形成的连通块数目的最大值

void add(int a, int b) {
    e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}

void tarjan(int u) {

    dfn[u] = low[u] = ++ timestamp;

    int s = 0;  // 如果当前点u是割点的话,去掉该点u得到的连通分量的个数
    for (int i = h[u]; ~i; i = ne[i]) {
        int j = e[i];
        if (!dfn[j]) {
            tarjan(j);
            low[u] = min(low[u], low[j]);
            if (dfn[u] <= low[j])  // 说明u是可能是割点, u存在一棵子树(删除割点u)
                s++;
        } else low[u] = min(low[u], dfn[j]);
    }

    //如果不是根节点
    /*
             /
            u    删掉u后 除子节点yi外
           / \           还要要加上父节点部分+1
          o   o
    */
    //最后还要加上父节点部分1
    if (u != root) s++;  // 不用加上&& s的判断,因为u不是割点的话,s要取1

    ans = max(ans, s);
}

int main() {

    while (scanf("%d%d", &n, &m), n || m) {

        memset(dfn, 0, sizeof dfn);  // dfn还具有判重数组的作用
        memset(h, -1, sizeof h);
        idx = timestamp = 0;

        while (m--) {
            int a, b;
            scanf("%d%d", &a, &b);
            add(a, b), add(b, a);
        }

        ans = 0;   //记录删除不同割点之后形成的连通块的最大值
        int cnt = 0;  // 记录连通块的数目
        //每次将其中联通块遍历,用tarjan
        for (root = 0; root < n; root++)  // 节点编号从0~n-1
            if (!dfn[root]) { //dfn数组兼判重数组,求联通块的数量
                cnt++;
                tarjan(root);
            }

        printf("%d\n", cnt + ans - 1);
    }

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Vic.GoodLuck

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值