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 mine is made up of a series of tunnels that meet at various large junctions. Unlike some owners, Digger actually cares about the welfare of his workers and has a concern
about the layout of the mine. Specifically, he worries that there may a junction which, in case of collapse, will cut off workers in one section of the mine from other workers (illudium phosdex, as you know, is highly unstable). To counter this, he wants to
install special escape shafts from the junctions to the surface. He could install one escape shaft at each junction, but Digger doesn’t care about his workers that much. Instead, he wants to install the minimum number of escape shafts so that if any of the
junctions collapses, all the workers who survive the junction collapse will have a path to the surface.

Write a program to calculate the minimum number of escape shafts and the total number of ways in which this minimum number of escape shafts can be installed.

Input

The input consists of several test cases. The first line of each case contains a positive integer N (N <= 5×10^4) indicating the number of mine tunnels. Following this are N lines each containing two distinct integers s and t, where
s and t are junction numbers. Junctions are numbered consecutively starting at 1. Each pair of junctions is joined by at most a single tunnel. Each set of mine tunnels forms one connected unit (that is, you can get from any one junction to any other).

The last test case is followed by a line containing a single zero.

Output

For each test case, display its case number followed by the minimum number of escape shafts needed for the system of mine tunnels and the total number of ways these escape shafts can be installed. You may assume that the result fits
in a signed 64-bit integer.

Follow the format of the sample output.

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

Source

2011WorldFinal

题意:

给你一个图,将上面一些点涂黑,使得去掉一个图中一个点之后每一个点都能到达一个黑点,求出最小放的点数以及方案数。

思路:

一个点双连通分量中,如果只有一个点为割点,那么这个分量必须在非割点的位置涂黑。问题就变为求解点双连通分量了。有一种特殊情况是,全图为一个分量,那么需任意涂两个点。

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
#define maxn 100005
#define MAXN 100005
#define INF 0x3f3f3f3f
#pragma comment (linker,"/STACK:102400000,102400000")
typedef long long ll;
using namespace std;

int n,m,cnt,tot,flag;
int lev,bcccnt;
int head[maxn];
int dfn[maxn],low[maxn];
bool vis[maxn],ok[maxn];
struct Node
{
    int v,w,next;
} edge[MAXN];
int stau[maxn],stav[maxn],top,bccno[maxn];
vector<int>bcc[maxn];

void addedge(int u,int v,int w)
{
    cnt++;
    edge[cnt].v=v;
    edge[cnt].w=w;
    edge[cnt].next=head[u];
    head[u]=cnt;
}
void Tarjan(int u,int pre)
{
    int i,j,t,v,num=0;
    low[u]=dfn[u]=++lev;
    for(i=head[u];i;i=edge[i].next)
    {
        v=edge[i].v;
        if(vis[v])
        {
            if(v!=pre) low[u]=min(low[u],dfn[v]);  // 桥不能用父亲来更新 割点随意
        }
        else
        {
            vis[v]=1;
            top++;
            stau[top]=u; stav[top]=v;
            num++;
            Tarjan(v,u);
            if(dfn[u]<=low[v])
            {
                if(pre!=0) ok[u]=1;  // 不是根
                bcccnt++;
                bcc[bcccnt].clear();
                while(!(stau[top]==u&&stav[top]==v))
                {
                    if(bccno[stav[top]]!=bcccnt) bccno[stav[top]]=bcccnt,bcc[bcccnt].push_back(stav[top]);
                    if(bccno[stau[top]]!=bcccnt) bccno[stau[top]]=bcccnt,bcc[bcccnt].push_back(stau[top]);
                    top--;
                }
                if(bccno[stav[top]]!=bcccnt) bccno[stav[top]]=bcccnt,bcc[bcccnt].push_back(stav[top]);
                if(bccno[stau[top]]!=bcccnt) bccno[stau[top]]=bcccnt,bcc[bcccnt].push_back(stau[top]);
                top--;
            }
            low[u]=min(low[u],low[v]);
        }
    }
    if(pre==0&&num>1) ok[u]=1;
}
int main()
{
    int i,j,t,u,v,w,ca=0;
    while(scanf("%d",&m),m)
    {
        cnt=n=0;
        memset(head,0,sizeof(head));
        for(i=1; i<=m; i++)  // 建图
        {
            scanf("%d%d",&u,&v);
            addedge(u,v,0);
            addedge(v,u,0);
            n=max(n,u);
            n=max(n,v);
        }
        memset(vis,0,sizeof(vis));
        memset(ok,0,sizeof(ok));
        memset(bccno,0,sizeof(bccno));
        bcccnt=0;
        for(i=1; i<=n; i++)// 割点或者桥的求解
        {
            if(vis[i]) continue ;
            lev=0;
            vis[i]=1;
            top=0;
            Tarjan(i,0);
        }
        ll ans=0,res=1;
        for(i=1;i<=bcccnt;i++)
        {
            int num=0;
            for(j=0;j<bcc[i].size();j++)
            {
                if(ok[bcc[i][j]]) num++;
            }
            if(num==1)
            {
                ans++; res*=(bcc[i].size()-1);
            }
        }
        if(bcccnt==1)
        {
            ans=2; res=ll(n)*ll(n-1)/2;
        }
        printf("Case %d: %I64d %I64d\n",++ca,ans,res);
    }
    return 0;
}
时间: 2024-10-12 15:01:35

hdu 3844 Mining Your Own Business (点双连通分量)的相关文章

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

HDU 3844 Mining Your Own Business(割点,变形,开栈,经典)

题意:给出一个连通图,要求将某些点涂黑,使得无论哪个点(包括相关的边)撤掉后能够成功使得剩下的所有点能够到达任意一个涂黑的点,颜料不多,涂黑的点越少越好,并输出要涂几个点和有多少种涂法. 思路: 要使得任意撤掉一个点都能使其他点能够到达黑点,那么点双连通分量能保证这点,那么就在同个点双连通分量内涂黑1个点.但是每个[点双连通分量]都涂吗?太浪费颜料了,那就缩点成树,只需要涂叶子即可,那就找度为1的缩点.但是种数呢?叶子内的点除了割点外都是可以涂黑的,因为如果黑色割点被撤掉,那么叶子中的其他点怎么

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 2242 考研路茫茫——空调教室 (双连通分量+树形DP)

题目地址:HDU 2242 先用双连通分量缩点,然后形成一棵树,然后在树上做树形DP,求出每个点的子树和.然后找最小值即可.需要注意一下重边的问题,第一次返回父节点时可以忽略,因为这是反向边,然后之后再返回的时候就不是反向边了.不能忽略了. 代码如下: #include <iostream> #include <string.h> #include <math.h> #include <queue> #include <algorithm> #i

Mining Your Own Business(点双联通)

题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=19845 大意:有一座地下矿, 有n条隧道相连, 任意两个连接点之间只有一条隧道相连接. 为了降低矿工的危险, 现在决定在连接点处建一些逃生装置, 使得不管哪个连接点倒塌, 不在此连接点的所有矿工都能逃生. 问安装最少的逃生装置, 及其安装的方案. 分析题可知, 这是求点双联通分量的, 我们只要把只有一个割点的点双联通分量安装一个逃生装置即可. 安装的方案数就是点双

UVALive - 5135 Mining Your Own Business(双连通分量)

题目大意:有N个矿井 ,由一些隧道连接起来,现在要修建尽量少的安全通道,使得无论哪里发生事故,所有人均能逃出,求建的最少的安全通道数量和方案数 解题思路:建安全通道的话,肯定不能建在割顶,因为割顶如果崩塌了,割顶所连接的双连通分量内的点就跑不掉了,还得在双连通分量里面再建点(上述为双连通分量内部只有一个割顶的情况),这样不划算,还不如直接在里面建点 如果一个双连通分量的内部割顶有多个的话,那么在这个双连通分量里面就可以不用建安全通道了,因为一个割顶崩塌了,还有其他点可以连向外面,所以,只考虑内部

UVALive 5135 Mining Your Own Business 双连通分量 2011final

题意:n条隧道由一些点连接而成,其中每条隧道链接两个连接点.任意两个连接点之间最多只有一条隧道.任务就是在这些连接点中,安装尽量少的太平井和逃生装置,使得不管哪个连接点倒塌,工人都能从其他太平井逃脱,求最少安装数量和方案. 思路:其实本题就相当于在一张无向图中,涂尽量少的黑点,使得任意删除哪个点,每个连通分量至少有一个黑点.因为不同的连通分量最多只有一个公共点,那一定是割点.可以发现,涂黑割点是不划算的,而且在 一个点-双连通分量中涂黑两个黑点也是不划算的.所以只有当点-双连通分量只有一个割点时

hdu3844 Mining Your Own Business,无向图的双连通分量

点击打开链接 无向图的双连通分量 #include<cstdio> #include<stack> #include<vector> #include<map> #include<algorithm> #include<cstring> #pragma comment(linker, "/STACK:102400000,102400000") using namespace std; typedef long lo