• 【BZOJ】2730: [HNOI2012]矿场搭建【Tarjan找割点】【分联通块割点个数】


    2730: [HNOI2012]矿场搭建

    Time Limit: 10 Sec  Memory Limit: 128 MB
    Submit: 3230  Solved: 1540
    [Submit][Status][Discuss]

    Description

    煤矿工地可以看成是由隧道连接挖煤点组成的无向图。为安全起见,希望在工地发生事故时所有挖煤点的工人都能有一条出路逃到救援出口处。于是矿主决定在某些挖煤点设立救援出口,使得无论哪一个挖煤点坍塌之后,其他挖煤点的工人都有一条道路通向救援出口。请写一个程序,用来计算至少需要设置几个救援出口,以及不同最少救援出口的设置方案总数。

    Input

    输入文件有若干组数据,每组数据的第一行是一个正整数 N(N≤500),表示工地的隧道数,接下来的 N 行每行是用空格隔开的两个整数 S 和 T,表示挖       S 与挖煤点 T 由隧道直接连接。输入数据以 0 结尾。

    Output

    输入文件中有多少组数据,输出文件 output.txt 中就有多少行。每行对应一组输入数据的 结果。其中第 i 行以 Case i: 开始(注意大小写,Case 与 i 之间有空格,i 与:之间无空格,: 之后有空格),其后是用空格隔开的两个正整数,第一个正整数表示对于第 i 组输入数据至少需 要设置几个救援出口,第二个正整数表示对于第 i 组输入数据不同最少救援出口的设置方案总 数。输入数据保证答案小于 2^64。输出格式参照以下输入输出样例。

    Sample Input

    9
    1 3
    4 1
    3 5
    1 2
    2 6
    1 5
    6 3
    1 6
    3 2
    6
    1 2
    1 3
    2 4
    2 5
    3 6
    3 7
    0

    Sample Output

    Case 1: 2 4
    Case 2: 4 1

    HINT

    Case 1 的四组解分别是(2,4),(3,4),(4,5),(4,6);

    Case 2 的一组解为(4,5,6,7)。

    Solution

    可以发现要找的特殊点的数量和图中割点有关。因为割点会把一个联通块分离成几块,导致中间断开,此时肯定需要增加安放的特殊点。

    当把割点删去后分离成多个点双联通分量。

    此时对每个点双进行讨论:

    如果点双中与0个割点相邻,那么需要在点双中新增两个特殊点,防止其中一个特殊点挂了。

    如果点双中与1个割点相邻,那么需要在点双中新增一个特殊点,为这个割点提供备用。

    如果点双中与2个割点相邻,那么不需要增加特殊点,一个割点挂了可以走另一个割点离开。

    然后就可以用乘法原理算出方案数了。

    Code

    #include<bits/stdc++.h>
    #define LL long long
    using namespace std;
    
    int n, m;
    
    struct Node {
        int u, v, nex;
    } Edge[100005];
    
    int stot, h[505];
    void add(int u, int v) {
        Edge[++stot] = (Node) {u, v, h[u]};
        h[u] = stot;
    }
    
    int dfn[505], low[505], idc, stk[505], tp, cut[505];
    void Tarjan(int u, int fa) {
        dfn[u] = low[u] = ++ idc;
        stk[++tp] = u;
        int son = 0;
        for(int i = h[u]; i; i = Edge[i].nex) {
            int v = Edge[i].v;
            if(i == (fa ^ 1))    continue;
            if(!dfn[v]) {
                son ++;
                Tarjan(v, i);
                low[u] = min(low[u], low[v]);
                if(low[v] >= dfn[u]) cut[u] = 1;
            } else    low[u] = min(low[u], dfn[v]);
        }
        if(fa == 0 && son == 1)    cut[u] = 0;
    }
    
    int siz, cut_num, cnt, color[505];
    void dfs(int u) {
        color[u] = cnt;
        if(cut[u])    return ;
        siz ++;
        for(int i = h[u]; i; i = Edge[i].nex) {
            int v = Edge[i].v; 
            if(cut[v] && color[v] != cnt) {
                cut_num ++; color[v] = cnt;
            }
            if(!color[v])    dfs(v);
        }
    }
    
    int main() {
        int ti = 0;
        while(~scanf("%d", &m)) {
            if(m == 0)    break;
            n = 0;
            stot = 1;    memset(h, 0, sizeof(h));
            cnt = 0;    tp = 0;        idc = 0;
            memset(dfn, 0, sizeof(dfn));
            memset(low, 0, sizeof(low));
            memset(color, 0, sizeof(color));
            memset(cut, 0, sizeof(cut));
            for(int i = 1; i <= m; i ++) {
                int u, v;
                scanf("%d%d", &u, &v);
                add(u, v);    add(v, u);
                n = max(max(n, v), u);
            }
            for(int i = 1; i <= n; i ++)    if(!dfn[i])    Tarjan(i, 0);
            LL ans1 = 0, ans2 = 1;
            for(int i = 1; i <= n; i ++) {
                if(!cut[i] && !color[i]) {
                    cnt ++;    siz = 0, cut_num = 0;    dfs(i);
                    if(cut_num == 0) { ans1 += 2; ans2 *= 1ll * (siz - 1) * siz / 2;}
                    if(cut_num == 1) { ans1 += 1; ans2 *= siz;}
                }
            }
            printf("Case %d: %lld %lld
    ", ++ti, ans1, ans2);
        }
        return 0;
    }
  • 相关阅读:
    美团前端面经-2020-估计是凉了
    JavaScript的垃圾回收机制与内存泄漏
    从输入URL到浏览器显示页面发生了哪些事情---个人理解
    let 、const 、var、function声明关键字的新理解
    前端中堆和栈的概念
    今天想好好的认真开始维护自己的博客
    关于org.apache.poi 导出excel时引发的No such file or directory
    MySQL查询本周、上周、本月、上个月份数据的sql代码
    为mybatis mapper xml文件添加注释遇到问题
    ubuntu使用中遇到问题及解决方法持续整理
  • 原文地址:https://www.cnblogs.com/wans-caesar-02111007/p/9867081.html
Copyright © 2020-2023  润新知