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;
}

时间: 2024-10-13 09:21:42

UVALive5135 - Mining Your Own Business(BCC)的相关文章

UVAlive5135 Mining Your Own Business(bcc)

题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=19845 [思路] 点-双连通分量. 求出bcc,对于每个bcc而言,最优的方案就是在每一个只有一个割点的bcc中安置一个逃生装置. [代码] 1 #include<cstdio> 2 #include<cstring> 3 #include<stack> 4 #include<vector> 5 #include<ios

UVALive-5135 Mining Your Own Business (无向图的双连通分量)

题目分析:在一张无向图中,将一些点涂上黑色,使得删掉图中任何一个点时,每个连通分量至少有一个黑点.问最少能涂几个黑点,并且在涂最少的情况下有几种方案. 题目分析:显然,一定不能涂割点.对于每一个连通分量,如果有1个割点,则必须涂上分量内除割点之外的任意一个点,如果有多个(2个及以上)割点,则这个分量不需要涂色.如果整张图都没有割点,那么任选两个点涂色即可,之所以要涂两个,是要防止删掉的电恰是黑点的情况. 代码如下: # include<iostream> # include<cstdio

UVA 1108 - Mining Your Own Business(双连通分量)

UVA 1108 - Mining Your Own Business 题目链接 题意:给定一个连通图,设置一个些安全点,使得其他任意一些节点崩塌后,其他点都能到一个安全点,问安全点最小数量和情况数 思路: #include <cstdio> #include <cstring> #include <vector> #include <stack> #include <map> using namespace std; const int N =

hdu 3844 Mining Your Own Business (点双连通分量)

Mining Your Own Business Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1392    Accepted Submission(s): 219 Problem Description John Digger is the owner of a large illudium phosdex mine. The m

HDU 3844 Mining Your Own Business

Mining Your Own Business Time Limit: 1000ms Memory Limit: 32768KB This problem will be judged on HDU. Original ID: 384464-bit integer IO format: %I64d      Java class name: Main John Digger is the owner of a large illudium phosdex mine. The mine is m

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

题目大意:有N个矿井 ,由一些隧道连接起来,现在要修建尽量少的安全通道,使得无论哪里发生事故,所有人均能逃出,求建的最少的安全通道数量和方案数 解题思路:建安全通道的话,肯定不能建在割顶,因为割顶如果崩塌了,割顶所连接的双连通分量内的点就跑不掉了,还得在双连通分量里面再建点(上述为双连通分量内部只有一个割顶的情况),这样不划算,还不如直接在里面建点 如果一个双连通分量的内部割顶有多个的话,那么在这个双连通分量里面就可以不用建安全通道了,因为一个割顶崩塌了,还有其他点可以连向外面,所以,只考虑内部

UVALive 5135 Mining Your Own Business 双连通分量 2011final

题意:n条隧道由一些点连接而成,其中每条隧道链接两个连接点.任意两个连接点之间最多只有一条隧道.任务就是在这些连接点中,安装尽量少的太平井和逃生装置,使得不管哪个连接点倒塌,工人都能从其他太平井逃脱,求最少安装数量和方案. 思路:其实本题就相当于在一张无向图中,涂尽量少的黑点,使得任意删除哪个点,每个连通分量至少有一个黑点.因为不同的连通分量最多只有一个公共点,那一定是割点.可以发现,涂黑割点是不划算的,而且在 一个点-双连通分量中涂黑两个黑点也是不划算的.所以只有当点-双连通分量只有一个割点时

【LA】5135 Mining Your Own Business

[算法]点双连通分量 [题解]详见<算法竞赛入门竞赛入门经典训练指南>P318-319 细节在代码中用important标注. #include<cstdio> #include<algorithm> #include<vector> #include<stack> #include<cstring> using namespace std; const int maxm=50010; struct edge{int u,v,from

UVA 1108 - Mining Your Own Business

刘汝佳书上都给出了完整的代码 在这里理一下思路: 由题意知肯定存在一个或者多个双连通分量: 假设某一个双连通分量有割顶.那太平井一定不能打在割顶上. 而是选择割顶之外的随意一个点: 假设没有割顶,则要在该双连通分量上打两个井 至于打井方案.见代码 #include <cstdio> #include <cstring> #include <vector> #include <stack> #include <map> using namespac