Mining Your Own Business(点双联通)

题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=19845

大意:有一座地下矿, 有n条隧道相连, 任意两个连接点之间只有一条隧道相连接。 为了降低矿工的危险, 现在决定在连接点处建一些逃生装置, 使得不管哪个连接点倒塌, 不在此连接点的所有矿工都能逃生。 问安装最少的逃生装置, 及其安装的方案。

分析题可知, 这是求点双联通分量的, 我们只要把只有一个割点的点双联通分量安装一个逃生装置即可。 安装的方案数就是点双联通中节点的个数减去1; 而当只有一个点双联通分量时只需要安装两个逃生装置, 方案数就是v*(v-1)/2;

#include<stdio.h>
#include<string.h>
#include<vector>
#include<stack>
#include<algorithm>
using namespace std;
const int maxn = 100000 + 10;
struct Edge
{
    int u, v;
    Edge(int i, int j) : u(i), v(j) {}
};
vector<int> G[maxn], bcc[maxn];
int low[maxn], dfn[maxn], bccno[maxn];
bool iscut[maxn];
int cur, cnt;
stack<Edge> S; //存边, 就不用处理割点可以同时存在不同的连通分量里了
void dfs(int u, int fa)
{
    dfn[u] = low[u] = ++cur;
    int child = 0;
    for(int i = 0; i < G[u].size(); i++)
    {
        int v = G[u][i];
        if(v == fa)
            continue;
        if(!dfn[v])
        {
            S.push(Edge(u, v));
            child++;
            dfs(v, u);
            low[u] = min(low[u], low[v]);
            if(dfn[u] <= low[v])  //u的子孙后代最早出现的时间不小于u出现的时间, u才能为割点
            {
                ++cnt;
                iscut[u] = true;
                bcc[cnt].clear();
                while(!S.empty())
                {
                    Edge x = S.top();
                    S.pop();
                    if(bccno[x.u] != cnt)
                    {
                        bcc[cnt].push_back(x.u);
                        bccno[x.u] = cnt;
                    }
                    if(bccno[x.v] != cnt)
                    {
                        bcc[cnt].push_back(x.v);
                        bccno[x.v] = cnt;
                    }
                    if(x.u==u && x.v==v)
                        break;
                }
            }
        }
        else if(dfn[v] < dfn[u])  //关于这个判断为什么不能用强联通和边双联通相同的 bccno[v]==0 判断, 请路过的大牛看到了给解释一下
        {
            S.push(Edge(u, v));
            low[u] = min(low[u], dfn[v]);
        }
    }
    if(fa<0 && child==1)  //在起点只有子节点时,起点不是割点
        iscut[u] = false;
}
void find_bcc(int n)
{
    cur = cnt = 0;
    memset(dfn, 0, sizeof(dfn));
    memset(iscut, false, sizeof(iscut));
    memset(bccno, 0, sizeof(bccno));
    dfs(1, -1);
}
int main()
{
    int n, a, b, t = 0;
    int m = 0;
    while(scanf("%d", &n), n)
    {
        for(int i = 0; i <= m; i++)
            G[i].clear();
        for(int i = 0; i < n; i++)
        {
            scanf("%d%d", &a, &b);
            m = max(m, max(a, b));
            G[a].push_back(b);
            G[b].push_back(a);
        }
        find_bcc(n);
        long long ans1 = 0, ans2 = 1;
        for(int i = 1; i <= cnt; i++)
        {
            int cnt_cut = 0;
            for(int j = 0; j < bcc[i].size(); j++)
            {
                int k = bcc[i][j];
                if(iscut[k])
                    cnt_cut++;
            }
            if(cnt_cut == 1)
            {
                ans1++;
                ans2 *= (long long)(bcc[i].size()-cnt_cut);
            }
        }
        if(cnt == 1)
        {
            ans1 = 2;
            ans2 = bcc[cnt].size() * (bcc[cnt].size()-1) / 2;
        }
        printf("Case %d: %lld %lld\n", ++t, ans1, ans2);
    }
    return 0;
}
时间: 2024-11-14 16:57:52

Mining Your Own Business(点双联通)的相关文章

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 =

UVA5135 Mining Your Own Business ( 无向图双连通分量)

题目链接 题意:n条隧道由一些点连接而成,其中每条隧道链接两个连接点.任意两个连接点之间最多只有一条隧道.任务就是在这些连接点中,安装尽量少的太平井和逃生装置,使得不管哪个连接点倒塌,工人都能从其他太平井逃脱,求最少安装数量和方案. 分析:本题相当于在一张无向图上选择尽量少的点涂黑(对应太平井),使任意一个点被删除后,每个连通分量都至少还有一个黑点.不同的连通分量最多有一个公共点即割点,将割点涂上是不划算的,因为删除割点后,要保证每个连通分量还要有黑点,所以还要在其他的连通分量中涂黑点,如果不涂

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

HDU 3844 Mining Your Own Business

Mining Your Own Business Time Limit: 1000ms Memory Limit: 32768KB This problem will be judged on HDU. Original ID: 384464-bit integer IO format: %I64d      Java class name: Main John Digger is the owner of a large illudium phosdex mine. The mine is m

hihocoder #1190 : 连通性&#183;四 点双联通分量

http://hihocoder.com/problemset/problem/1190?sid=1051696 先抄袭一下 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi和小Ho从约翰家回到学校时,网络所的老师又找到了小Hi和小Ho. 老师告诉小Hi和小Ho:之前的分组出了点问题,当服务器(上次是连接)发生宕机的时候,在同一组的服务器有可能连接不上,所以他们希望重新进行一次分组.这一次老师希望对连接进行分组,并把一个组内的所有连接关联的服务器也视为这个组内

[HDOJ4738]Caocao&#39;s Bridges(双联通分量,割边,tarjan)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4738 给一张无向图,每一条边都有权值.找一条割边,使得删掉这条边双连通分量数量增加,求权值最小那条. 注意有重边,ACEveryDay里群巨给的意见是tarjan的时候记录当前点是从哪条边来的. 注意假如桥的权值是0的时候也得有一个人去炸…… 1 /* 2 ━━━━━┒ギリギリ♂ eye! 3 ┓┏┓┏┓┃キリキリ♂ mind! 4 ┛┗┛┗┛┃\○/ 5 ┓┏┓┏┓┃ / 6 ┛┗┛┗┛┃ノ) 7

UVA - 10765 Doves and bombs (双联通分量)

链接 :  http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=34798 给N个点的无向图并且联通,问删除每次一个点之后还剩多少联通分量. 找割顶 如果删除的是割顶 联通分量就会增加,否则还是1(因为原图是联通图),删除割顶之后 联通块的数目 就要看该割顶在几个双联通分量里出现过. #pragma comment(linker, "/STACK:10240000,10240000") #include <a

POJ 3177 Redundant Paths(边双联通图)

Description In order to get from one of the F (1 <= F <= 5,000) grazing fields (which are numbered 1..F) to another field, Bessie and the rest of the herd are forced to cross near the Tree of Rotten Apples. The cows are now tired of often being forc

HDU 4612 Warm up(边双联通求树的直径)

Problem Description N planets are connected by M bidirectional channels that allow instant transportation. It's always possible to travel between any two planets through these channels. If we can isolate some planets from others by breaking only one