码迷,mamicode.com
首页 > 其他好文 > 详细

UVALive - 5135 Mining Your Own Business(双连通分量)

时间:2015-08-07 23:59:38      阅读:405      评论:0      收藏:0      [点我收藏+]

标签:

题目大意:有N个矿井 ,由一些隧道连接起来,现在要修建尽量少的安全通道,使得无论哪里发生事故,所有人均能逃出,求建的最少的安全通道数量和方案数

解题思路:建安全通道的话,肯定不能建在割顶,因为割顶如果崩塌了,割顶所连接的双连通分量内的点就跑不掉了,还得在双连通分量里面再建点(上述为双连通分量内部只有一个割顶的情况),这样不划算,还不如直接在里面建点
如果一个双连通分量的内部割顶有多个的话,那么在这个双连通分量里面就可以不用建安全通道了,因为一个割顶崩塌了,还有其他点可以连向外面,所以,只考虑内部只有一个割顶的双连通分量要怎么建安全通道
怎么建呢,排除掉割顶的所有的点都可以建

假设ans1代表所需要建立的安全通道的数量,ans2代表建立的方案数,那么找到内部只有一个割顶的双连通分量时(双连通分量的内部结点有n个,排除掉割顶的话,还有n-1种建立的方案)
那么ans1 = ans1 + 1; ans2 *= (n - 1)

如果给的图形成的是一个双连通分量(假设有n个点),只有一个,那么需要建立2个安全通道(一个倒塌了,还有另一个),方案数为n * (n - 1) / 2

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <stack>
#include <queue>
#include <stack>
using namespace std;
#define N 100010
#define INF 0x3f3f3f3f
#define ll long long

struct Edge{
    int to, next;
}E[N];

struct Node {
    int u, v;
    Node() {}
    Node(int u, int v): u(u), v(v) {}
};

int pre[N], iscut[N], bccno[N], head[N], dfs_clock, bcc_cnt;
int n, tot, Max;
vector<int> bcc[N];
stack<Node> S;

void AddEdge(int from, int to) {
    E[tot].to = to;
    E[tot].next = head[from];
    head[from] = tot++;
}

void init() {
    memset(head, -1, sizeof(head));
    tot = 0;

    int u, v;
    Max = -INF;
    for (int i = 0; i < n; i++) {
        scanf("%d%d", &u, &v);
        u--; v--;
        AddEdge(u, v);
        AddEdge(v, u);
        if (u > Max || v > Max) {
            Max = max(u, v);
        }
    }
}

int dfs(int u, int fa) {
    int lowu = pre[u] = ++dfs_clock;
    int child = 0;

    for (int i = head[u]; i != -1; i = E[i].next) {
        int v = E[i].to;
        Node e = Node(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();
                while (1) {
                    Node t = S.top();
                    S.pop();

                    if (bccno[t.u] != bcc_cnt) {
                        bcc[bcc_cnt].push_back(t.u);
                        bccno[t.u] = bcc_cnt;
                    }
                    if (bccno[t.v] != bcc_cnt) {
                        bcc[bcc_cnt].push_back(t.v);
                        bccno[t.v] = bcc_cnt;
                    }
                    if (t.u == u && t.v == v)
                        break;
                }
            }
        }
        else if(pre[v] < pre[u] && v != fa) {
            lowu = min(pre[v], lowu);
            S.push(e);
        }
    }
    if (fa < 0 && child == 1)
        iscut[u] = false;
    return lowu;
}

int cas = 1;

void solve() {
    memset(pre, 0, sizeof(pre));
    memset(iscut, 0, sizeof(iscut));
    memset(bccno, 0, sizeof(bccno));

    dfs_clock = bcc_cnt = 0;

    for (int i = 0; i <= Max; i++)
        if (!pre[i])
            dfs(i, -1);

    ll ans1 = 0, ans2 = 1;

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

int main() {
    while(scanf("%d", &n) != EOF && n) {
        init();
        solve();
    }
    return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

UVALive - 5135 Mining Your Own Business(双连通分量)

标签:

原文地址:http://blog.csdn.net/l123012013048/article/details/47347023

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!