【算法练习】HDU - 3844 Mining Your Own Business (双连通分量-割点)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/pengwill97/article/details/81979635

题意

有一座地下的稀有金属矿由n条隧道和一些连接点组成,其中每条隧道连接两个连接点,任意两个连接点之间最多只有一条隧道。为了降低矿工的危险,你的任务是在一些连接点处安装太平井和相应的逃生装置,使得不管哪个连接点倒塌,不在此连接点的所有矿工都能到达太平井逃生(假定除了倒塌的连接点不能通行外,其他隧道和连接点完好无损)。为了节约成本,比应当在尽量少的连接点安装太平井。还需要计算出当太平井的数目最小时的总方案数。

题解

每个只有一个割点的bcc中,任选一个点即可。
为啥在只有一个割点的bcc中呢,考虑如下的情况。
这里写图片描述
1. 直接看样例的case2,其中1和2都是割点。当然我们知道割点都不选,所以这个是特殊情况,也就是在1和2组成的bcc中,我们都不选择。
2. 考虑上图的情况。图中2和5都是割点,于是有3个bcc,分别是1、2组成的bcc,2,、3、4、5组成的bcc和5、6组成的bcc。最佳选择是1和6分别选择。但是如果按照不是只有一个割点的bcc中任选一个,那么在中间的2、3、4、5组成的bcc中就会选出一个(因为他有两个割点)。这样显然不是最优的。

代码

#include<bits/stdc++.h>
using namespace std;
typedef double db;
typedef long long ll;
typedef unsigned long long ull;
const int nmax = 5e4+7;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
const ull p = 67;
const ull MOD = 1610612741;
int n, tot;
int head[nmax];
int dfn[nmax], low[nmax], dfs_clock, bcc_cnt, bccno[nmax], cut_cnt;
bool iscut[nmax];
struct edge{
    int to, nxt;
}e[nmax <<1];
typedef pair<int, int> pii;
vector<int> bcc[nmax];
pii sstack[nmax];
int st;
void add_edge(int u, int v) {
    e[tot].to = v;
    e[tot].nxt = head[u];
    head[u] = tot++;
}
void tarjan(int u, int fa) {
    dfn[u] = low[u] = ++dfs_clock;
    int child = 0;
    for(int i = head[u]; i != -1; i = e[i].nxt) {
        int v = e[i].to;
        if(!dfn[v]) {
            child ++;
            sstack[st++] = make_pair(u, v);
            tarjan(v, u);
            low[u] = min(low[u], low[v]);
            if(low[v] >= dfn[u]) {
                iscut[u] = true;
                cut_cnt ++;
                bcc_cnt ++;
                bcc[bcc_cnt].clear();
                for(;;) {
                    pii tmp = sstack[--st];
                    if(bccno[tmp.first] != bcc_cnt) {
//                        if(iscut[tmp.first] == false)
                            bcc[bcc_cnt].push_back(tmp.first);
                        bccno[tmp.first] = bcc_cnt;
                    }
                    if(bccno[tmp.second] != bcc_cnt) {
//                        if(iscut[tmp.second] == false)
                            bcc[bcc_cnt].push_back(tmp.second);
                        bccno[tmp.second] = bcc_cnt;
                    }
                    if(tmp.first == u && tmp.second == v || tmp.first == v && tmp.second == u)
                        break;
                }
            }
        } else if(v != fa && dfn[v] < dfn[u]) {
            sstack[st++] = make_pair(u, v);
            low[u] = min(low[u], dfn[v]);
        }
    }

    if(fa == -1 && child <= 1) {
        iscut[u] = false;
        cut_cnt --;
    }
}
int main(){
    int kase = 1;
    while(scanf("%d", &n) && n) {
        memset(head, -1, sizeof head);
        memset(dfn, 0, sizeof dfn);
        memset(low ,0, sizeof low);
        memset(iscut, 0, sizeof iscut);
        memset(bccno, 0, sizeof bccno);
        cut_cnt = bcc_cnt = st = dfs_clock = tot = 0;
        int mx = 0;
        for(int i = 1; i <= n; ++i) {
            int u, v;
            scanf("%d %d", &u, &v);
            mx = max(mx , max(u, v));
            add_edge(u, v);
            add_edge(v, u);
        }
        for(int i = 1; i <= mx; ++i) {
            if(!dfn[i])
                tarjan(i, -1);
        }

//        for(int i = 1; i <= bcc_cnt; ++i) {
//            printf("debug %d :", i);
//            for(int j = 0; j < bcc[i].size(); ++j) {
//                printf(" %d", bcc[i][j]);
//            }
//            printf("\n");
//        }
        printf("Case %d: ", kase ++);
        ll ans = 1;
        if(bcc_cnt == 1) {
            ans = 1ll * mx * (mx-1) / 2;
            printf("%d %lld\n", 2, ans);
        } else {
            int cnt = 0;
            for(int i = 1; i <= bcc_cnt; ++i) {
                int cut_num = 0;
                for(int j = 0; j < bcc[i].size(); ++j) {
                    if(iscut[bcc[i][j]])
                        cut_num ++;
                }
                if(cut_num == 1) {
                    cnt ++;
                    ans = ans * ( 1ll * (bcc[i].size() - cut_num) );
                }
            }
            printf("%d %lld\n", cnt, ans);
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/pengwill97/article/details/81979635
今日推荐