7_13_B题 Boonie and Clyde(tarjan求割点)

7_13_B题 Boonie and Clyde


题意

给出一张图,要求删去两个点,使图不连通,问有多少种删法。

思路

先tarjan求出所有割点,然后枚举要删去的第一个点,如果该点不是割点,则下一个点必须是割点,如果该点是割点,则要分类讨论,如果形成了三个或三个以上的连通块,则可任选下一点,如果形成了两个连通块,要分别考虑两边都只有一个点,有一边只有一个点的情况,再分别更新答案就行了

代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;
const int maxn = 1e3 + 10;

int n, m, del, child, num;
int dfn[maxn], low[maxn], bricnt, times;
vector<int> G[maxn];
void init (){
    memset(dfn, -1, sizeof(dfn));
    memset(low, -1, sizeof(low));
}
inline void addedge(int from, int to){
    G[from].push_back(to);
    G[to].push_back(from);
}
void Tarjan(int cur , int from) {
    dfn[cur] = low[cur] = ++times;
    for(int i = 0; i < G[cur].size(); i++){
        int to = G[cur][i];
        if(to == del || to == from)continue;
        if(dfn[to] == -1) {
            Tarjan(to, cur);
            low[cur] = min(low[cur] , low[to]);
            if(from == 0) {
                child++;
                continue;
            }
            if(low[to] >= dfn[cur])
                bricnt++;
        }
        else
            low[cur] = min(low[cur] , dfn[to]);
    }
}

int main() {
    int kas = 1;
    while(~scanf("%d %d", &n, &m) && (n + m)) {
        while(m--) {
            int u , v;
            scanf("%d %d", &u, &v);
            addedge(u, v);
        }
        printf("Case %d: ", kas++);
        int ans = 0, sonnum;
        for(del = 1; del <= n; del++) {
            init();
            int cnt = bricnt = sonnum = 0;
            for(int i = 1; i <= n; i++)
                if(i != del && dfn[i] == -1) {
                    cnt++;
                    times = child = 0;
                    Tarjan(i, 0);
                    if(times == 1) {
                        sonnum++;
                        continue;
                    }
                    if(child > 1) bricnt++ ;
                }
            if(cnt > 2)ans += (n - 1);
            else if(cnt == 2 && sonnum == 0)ans += (n - 1);
            else if(cnt == 2 && sonnum == 1)ans += (n - 2);
            else if(cnt == 1)ans += bricnt;
        }
        printf("%d\n", ans / 2);
        for(int i = 1; i <= n; i++) G[i].clear();
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值