UVALive5135 - Mining Your Own Business(BCC)

题目链接


题意:n条隧道由一些点连接而成,其中每条隧道链接两个连接点。任意两个连接点之间最多只有一条隧道。任务就是在这些连接点中,安装尽量少的太平井和逃生装置,使得不管哪个连接点倒塌,工人都能从其他太平井逃脱,求最少安装数量和方案。

思路:其实本题就相当于在一张无向图中,涂尽量少的黑点,使得任意删除哪个点,每个连通分量至少有一个黑点。因为不同的连通分量最多只有一个公共点,那一定是割点。可以发现,涂黑割点是不划算的,而且在一个点-双连通分量中涂黑两个黑点也是不划算的。所以只有当点-双连通分量只有一个割点时,才需要涂,而且是任选一个非割点涂黑。

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <stack>
#include <algorithm>

using namespace std;

typedef long long ll;

const int MAXN = 50005;

struct edge{
    edge() {}
    edge(int uu, int vv) {
        u = uu; 
        v = vv;
    }
    int u, v;
};

vector<int> g[MAXN], bcc[MAXN];
stack<edge> s;
int pre[MAXN], iscut[MAXN], bccno[MAXN];
int n, dfs_clock, bcc_cnt, tmp;

int dfs(int u, int fa) {
    int lowu = pre[u] = ++dfs_clock;
    int child = 0;
    for (int i = 0; i < g[u].size(); i++) {
        int v = g[u][i]; 
        edge e(u, v); 
        if (!pre[v]) {
            s.push(e);
            child++;
            int lowv = dfs(v, u);
            lowu = min(lowu, lowv);
            if (lowv >= pre[u]) {
                iscut[u] = true; 
                bcc_cnt++; 
                bcc[bcc_cnt].clear();
                for (;;) {
                    edge x = s.top(); 
                    s.pop(); 
                    if (bccno[x.u] != bcc_cnt) {
                        bcc[bcc_cnt].push_back(x.u);
                        bccno[x.u] = bcc_cnt;
                    }
                    if (bccno[x.v] != bcc_cnt) {
                        bcc[bcc_cnt].push_back(x.v);
                        bccno[x.v] = bcc_cnt;
                    }
                    if (x.u == u && x.v == v) break;
                }
            }
        }
        else if (pre[v] < pre[u] && v != fa) {
            s.push(e); 
            lowu = min(lowu, pre[v]);
        }
    }
    if (fa < 0 && child == 1) iscut[u] = 0;
    return lowu;
}

void find_bcc(int n) {
    memset(pre, 0, sizeof(pre));
    memset(iscut, 0, sizeof(iscut));
    memset(bccno, 0, sizeof(bccno));
    dfs_clock = bcc_cnt = 0;
    for (int i = 1; i <= n; i++)
        if (!pre[i])
            dfs(i, -1);
}

int main() {
    int t = 1;
    while (scanf("%d", &n) && n) {
        int u, v; 
        for (int i = 0; i < MAXN; i++)
            g[i].clear();
        tmp = 0;
        for (int i = 0; i < n; i++) {
            scanf("%d%d", &u, &v);
            g[u].push_back(v);
            g[v].push_back(u);
            tmp = max(max(tmp, u), v);
        } 
        find_bcc(tmp);

        ll ans1 = 0, ans2 = 1;
        if (bcc_cnt == 1) {
            ans1 = 2; 
            ans2 = bcc[1].size() * (bcc[1].size() - 1) / 2;
        }
        else {
            for (int i = 1; i <= bcc_cnt; i++) {
                int cnt_cnt = 0; 
                for (int j = 0; j < bcc[i].size(); j++) 
                    if (iscut[bcc[i][j]])
                        cnt_cnt++;
                if (cnt_cnt == 1) {
                    ans1++; 
                    ans2 *= (ll)(bcc[i].size() - cnt_cnt);
                }
            } 
        }
        printf("Case %d: %lld %lld\n", t++, ans1, ans2);
    } 
    return 0;
}


你可能感兴趣的:(UVALive5135 - Mining Your Own Business(BCC))