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

题目大意:有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;
}

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

时间: 2024-08-05 11:16:08

UVALive - 5135 Mining Your Own Business(双连通分量)的相关文章

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

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

UVALive 5135 Mining Your Own Business

题意: 一些隧道组成矿井  现在要修建尽量少的逃生通道  使得无论哪里发生事故  所有人均能逃出  求方案数 思路: 这道题比较容易联想到割点  因为只有这种点出事矿井才会不连通  那么首先就找出所有割点 分析最少要建几个逃生通道  那当然是每个连通块各一个  因此需要把求出连通块顶点数之积 最后考虑特殊情况  没有割点  那么随便两个地方建就好了  不能建一个  万一就那里出事了呢- 代码: #include<cstdio> #include<cstring> #include&

【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

LA 5135 井下矿工(点—双连通分量模板题)

https://vjudge.net/problem/UVALive-5135 题意:在一个无向图上选择尽量少的点涂黑,使得任意删除一个点后,每个连通分量至少有一个黑点. 思路: 首先dfs遍历求出割顶和双连通分量,并把每个连通分量保存下来. 接下来分情况讨论: 如果一个点—双连通分量只有一个割顶,在该分量中必须将一个非割顶涂黑. 如果一个点—双连通分量有2个及以上的割顶,不需要涂黑. 如果整个图没有割顶,则至少需要涂黑两个点.(因为有可能删除的就是涂黑的点) 1 #include<iostre

UVALive 5135 Mining Your Own Bussiness【tarjan点双】

LINK1 LINK2 题目大意 给你一个无向连通图,让你给一些点染上黑色,需要满足染色之后,断开任意一个节点,要满足任意一个联通块中剩下的节点中至少有一个黑点 思路 一开始想的是把每一个点双联通分量都把除了割点的size乘上 然后发现随手卡掉 然后发现一下性质 首先所有相邻点双联通分量一定有公共的割点 如果一个双联通分量里面只包含了一个割点,那么如果断掉这个割点那么这个双联通分量就被孤立了 所以这样的双联通分量至少选择一个点 然后如果一个双联通分量有大于等于两个割点,就算一个被割掉了另外一边至

LA 5135 Mining Your Own Business

求出 bcc 后再……根据大白书上的思路即可. 然后我用的是自定义的 stack 类模板: 1 #include<cstdio> 2 #include<cstring> 3 #include<vector> 4 //#include<stack> 5 #include<stdexcept> 6 #include<algorithm> 7 using namespace std; 8 typedef long long LL; 9 co

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

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 =

hdu3844 Mining Your Own Business,无向图的双连通分量

点击打开链接 无向图的双连通分量 #include<cstdio> #include<stack> #include<vector> #include<map> #include<algorithm> #include<cstring> #pragma comment(linker, "/STACK:102400000,102400000") using namespace std; typedef long lo