zoukankan      html  css  js  c++  java
  • [Luogu] P3225 [HNOI2012]矿场搭建

    题目描述

    煤矿工地可以看成是由隧道连接挖煤点组成的无向图。为安全起见,希望在工地发生事故时所有挖煤点的工人都能有一条出路逃到救援出口处。于是矿主决定在某些挖煤点设立救援出口,使得无论哪一个挖煤点坍塌之后,其他挖煤点的工人都有一条道路通向救援出口。

    请写一个程序,用来计算至少需要设置几个救援出口,以及不同最少救援出口的设置方案总数。

    题目解析

    tarjan找双联通分量,找割点。

    在一个分量里有 ≥2 个割点,这个分量就怎么都能跑出去,不需要建出口。

    在一个分量里有 1 个割点,这个分量就要防止割点塌了,需要建1个出口。

    在一个分量里没有割点,说明它不和别的分量连通,为了防止出口塌掉,要建两个出口。

    看起来有些坑,值得注意的是,一个点只会在一个强连通分量,但可能同时处于多个双联通分量

    Code

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    
    const int MAXN = 500 + 5;
    
    struct Edge {
        int nxt;
        int to;
    } l[MAXN<<1];
    
    int n,m,res,T;
    int tot,stamp;
    int head[MAXN],cnt;
    int low[MAXN],dfn[MAXN];
    int sum,num;
    int root,deg;
    int vis[MAXN],col[MAXN];
    bool cut[MAXN];
    long long ans1,ans2 = 1;
    
    void tarjan(int x,int from) {
        dfn[x] = low[x] = ++stamp;
        for(int i = head[x];i;i = l[i].nxt) {
            if(!dfn[l[i].to]) {
                tarjan(l[i].to,x);
                low[x] = min(low[x],low[l[i].to]);
                if(low[l[i].to] >= dfn[x]) {
                    if(x == root) deg++;
                    else cut[x] = true;
                }
            } else if(l[i].to != from) low[x] = min(low[x],dfn[l[i].to]);
        }
        return;
    }
    
    void dfs(int x) {
        vis[x] = tot;
        if(cut[x]) return;
        sum++;
        for(int i = head[x];i;i = l[i].nxt) {
            if(cut[l[i].to] && vis[l[i].to] != tot) num++,vis[l[i].to] = tot;
            if(!vis[l[i].to]) dfs(l[i].to);
        } 
    }
    
    inline void add(int x,int y) {
        cnt++;
        l[cnt].nxt = head[x];
        l[cnt].to = y;
        head[x] = cnt;
        return;
    }
    
    inline void clean() {
        memset(low,0,sizeof(low));
        memset(dfn,0,sizeof(dfn));
        memset(head,0,sizeof(head));
        memset(col,0,sizeof(col));
        memset(cut,0,sizeof(cut));
        memset(vis,0,sizeof(vis));
        num = sum = 0;
        ans1 = n = tot = stamp = cnt = 0;
        ans2 = 1;
    }
    
    int main() {
        while(~scanf("%d",&m) && m) {
            clean();
            int x,y;
            for(int i = 1;i <= m;i++) {
                scanf("%d%d",&x,&y);
                n = max(n,max(x,y));
                add(x,y),add(y,x);
            }
            for(int i = 1;i <= n;i++) {
                if(!dfn[i]) {
                    deg = 0;
                    tarjan(root = i,0);
                    if(deg >= 2) cut[root] = true;
                }
            }
            for(int i = 1;i <= n;i++) {
                if(!vis[i] && !cut[i]) {
                    tot++;
                    sum = num = 0;
                    dfs(i);
                    if(!num && sum > 1) ans1 += 2, ans2 *= sum*(sum-1)/2;
                    else if(num == 1) ans1++, ans2 *= sum;
                }
            }
            printf("Case %d: %lld %lld
    ",++T,ans1,ans2);
        }
        return 0;
    }
  • 相关阅读:
    Linux学习65 实战使用awk高级功能统计网络请求连接状态
    Linux学习64 awk使用与实战
    Linux学习63 shell脚本高级编程-信号捕捉实战
    Linux学习62 shell脚本高级编程-数组和字符串处理
    Linux学习61 企业军工级别安全策略-SELinux简介
    Linux学习60 centos7新特性-systemd及systemctl实战
    Linux学习59 shell脚本高级用法-函数编程与应用实战
    【HBase】HBase与MapReduce的集成案例
    【HBase】底层原理
    【HBase】Java实现过滤器查询
  • 原文地址:https://www.cnblogs.com/floatiy/p/9708207.html
Copyright © 2011-2022 走看看