[题解]P3225 [HNOI2012]矿场搭建

题意

给定一个无向图,问最少在几个点上设置出口,可以使得不管其他哪个点坍塌,其余所有点都可以与某个出口相连。

思路

对于这道题,我们有以下几个技巧:

  1. 对于每一个连通块出口数量必须大于等于 2
  2. 因为,如果出口数量为 1,那么,如果刚好在出口坍塌了,就出不去了。
  3. 分别看每一个连通块。
  4. 这里要分三种情况来讨论:
    • 点双连通分量的度数为 0。(没有割点)。假设当前连通块的节点数量为 s 个,那么,方案数就为:Cs2。即:s×(s1)2
    • 点双连通分量的度数为 1。则需要在连通分量内部设置一个出口。
    • 点双连通分量的度数大于 1。则不需要设置出口。

Code

#include <bits/stdc++.h>  
#define re register  
  
using namespace std;  
  
typedef unsigned long long ull;  
const int N = 510,M = 1e3 + 10;  
int n,m,idx,tim,num,opt,root;  
int h[N],ne[M],e[M];  
int dfn[N],low[N],vis[N];  
stack<int> s;  
vector<int> g[N];  
  
inline int read(){  
    int r = 0,w = 1;  
    char c = getchar();  
    while (c < '0' || c > '9'){  
        if (c == '-') w = -1;  
        c = getchar();  
    }  
    while (c >= '0' && c <= '9'){  
        r = (r << 3) + (r << 1) + (c ^ 48);  
        c = getchar();  
    }  
    return r * w;  
}  
  
inline void add(int a,int b){  
    ne[idx] = h[a];  
    e[idx] = b;  
    h[a] = idx++;  
}  
  
inline void tarjan(int u){//缩点   
    int cnt = 0;  
    dfn[u] = low[u] = ++tim;  
    s.push(u);  
    if (u == root && !~h[u]){  
        g[++num].push_back(u);  
        return;  
    }  
    for (re int i = h[u];~i;i = ne[i]){  
        int j = e[i];  
        if (!dfn[j]){  
            tarjan(j);  
            low[u] = min(low[u],low[j]);  
            if (dfn[u] <= low[j]){  
                cnt++;  
                if (u != root || cnt > 1) vis[u] = true;  
                int x;  
                num++;  
                do{  
                    x = s.top();  
                    s.pop();  
                    g[num].push_back(x);  
                }while (x != j);  
                g[num].push_back(u);  
            }  
        }  
        else low[u] = min(low[u],dfn[j]);  
    }  
}  
  
int main(){  
    while (m = read()){  
        int res = 0;//初始化   
        ull ans = 1;  
        for (re int i = 1;i <= n;i++) g[i].clear();  
        idx = tim = num = n = 0;  
        memset(h,-1,sizeof(h));  
        memset(dfn,0,sizeof(dfn));  
        memset(vis,false,sizeof(vis));  
        while (!s.empty()) s.pop();  
        for (re int i = 1;i <= m;i++){  
            int a,b;  
            a = read();  
            b = read();  
            n = max(n,max(a,b));  
            add(a,b);  
            add(b,a);  
        }  
        for (re int i = 1;i <= n;i++){  
            if (!dfn[i]){  
                root = i;  
                tarjan(i);  
            }  
        }  
        for (re int i = 1;i <= num;i++){  
            int cnt = 0;  
            int len = g[i].size();  
            for (auto u:g[i]){  
                if (vis[u]) cnt++;//统计度   
            }  
            if (!cnt){//分情况讨论   
                if (len > 1){  
                    res += 2;  
                    ans *= len * (len - 1) >> 1;  
                }  
                else res++;  
            }  
            else if (cnt == 1){  
                res++;  
                ans *= (len - 1);  
            }  
        }  
        printf("Case %d: %d %llu\n",++opt,res,ans);  
    }  
    return 0;  
}  

作者:WaterSun

出处:https://www.cnblogs.com/WaterSun/p/18268795

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

posted @   WBIKPS  阅读(13)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
more_horiz
keyboard_arrow_up dark_mode palette
选择主题
点击右上角即可分享
微信分享提示