P3225 [HNOI2012]矿场搭建

题目描述

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

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

输入输出格式

输入格式:

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

输出格式:

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

输入输出样例

输入样例#1:

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
输出样例#1:

Case 1: 2 4
Case 2: 4 1

说明

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

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

分情况讨论:

很显然是要求割点嘛、、、(分类上写着、、、)

好吧,求完割点以后干什么??

我一直认为是先求出割点,然后将割点全部炸掉(屏蔽)后求出每个联通块的点的个数,然后在用乘法原理来做。

结果发现全wa!!!(ORZ)

据说这道题要分类讨论、、、、

①若一个双联通中没有割点,那么最少需要两个出口(炸了一个去另一个)

②若一个双联通能连到一个割点,那么最少需要在双联通中设置一个出口,炸了割点还能逃生、

③若一个双联通能连到多余一个割点,那么不管怎么炸,都能从没炸的割点跑到别的分量里

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define N 510
using namespace std;
long long ans2;
bool vis[N],cut_point[N];
int n,m,x,y,s,tot,tim,cnt,cut,sum,ans1;
int dfn[N],low[N],head[N],belong[N];
int read()
{
    ,f=; char ch=getchar();
    ; ch=getchar();}
    +ch-'; ch=getchar();}
    return x*f;
}
struct Edge
{
    int from,to,next;
}edge[N<<];
int add(int x,int y)
{
    tot++;
    edge[tot].to=y;
    edge[tot].next=head[x];
    head[x]=tot;
}
int begin()
{
    memset(vis,,sizeof(vis));
    memset(dfn,,sizeof(dfn));
    memset(low,,sizeof(low));
    memset(edge,,sizeof(edge));
    memset(head,,sizeof(head));
    memset(belong,,sizeof(belong));
    memset(cut_point,,sizeof(cut_point));
    n=,tot=,ans1=,ans2=,tim=,sum=;
}
int tarjan(int now,int pre)
{
    dfn[now]=low[now]=++tim;
    ; bool boo=false;
    for(int i=head[now];i;i=edge[i].next)
    {
        int t=edge[i].to;
        ^i)==pre) continue;
        if(!dfn[t])
        {
            tt++;tarjan(t,i);
            low[now]=min(low[now],low[t]);
            if(dfn[now]<=low[t]) boo=true;
        }
        else low[now]=min(low[now],dfn[t]);
    }
    ) {) cut_point[now]=true;}
    else if(boo) cut_point[now]=true;
}
int dfs(int x)
{
    s++;
    vis[x]=true;
    belong[x]=sum;
    for(int i=head[x];i;i=edge[i].next)
    {
        int t=edge[i].to;
        if(cut_point[t]&&belong[t]!=sum) cut++,belong[t]=sum;
        if(!vis[t]&&!cut_point[t]) dfs(t);
    }
}
int main()
{
    )
    {
        m=read();) break;
        begin();
        ;i<=m;i++)
        {
            x=read(),y=read();
            add(x,y),add(y,x);
            n=max(max(x,y),n);
        }
        ;i<=n;i++)
         );
        ;i<=n;i++)
        {
            if(vis[i]||cut_point[i]) continue;
            s=,cut=;
            sum++;dfs(i);
            ,ans2*=()>>);
            ) ans1++,ans2*=(long long)s;
        }
        printf("Case %d: %d %lld\n",++cnt,ans1,ans2);
    }
    ;
}

傻不拉几的只考虑一种情况还调试半天、、、、结果全wa

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define N 11000
using namespace std;
bool vis[N],cut_point[N];
int n,m,tot,tim,sum,cnt,top,ans1,ans2;
int x[N],y[N],dfn[N],low[N],ans[N],head[N],stack[N],belong[N];
int read()
{
    ,f=; char ch=getchar();
    ; ch=getchar();}
    +ch-'; ch=getchar();}
    return x*f;
}
struct Edge
{
    int from,to,next;
}edge[N];
int add(int x,int y)
{
    tot++;
    edge[tot].to=y;
    edge[tot].next=head[x];
    head[x]=tot;
}
int tarjan(int x,int pre)
{
    ; bool boo;
    dfn[x]=low[x]=++tim;
    vis[x]=true;
    for(int i=head[x];i;i=edge[i].next)
    {
        int t=edge[i].to;
        ^i)==pre) continue;
         if(!vis[t])
        {
            s++;tarjan(t,i);
            low[x]=min(low[t],low[x]);
            if(low[t]>=dfn[x]) boo=true;
        }
        else low[x]=min(low[x],dfn[t]);
    }
    ) cut_point[x]=true;}
    else {if(boo) cut_point[x]=true;}
}
int tarjan1(int now)
{
    dfn[now]=low[now]=++tim;
    stack[++top]=now;vis[now]=true;
    for(int i=head[now];i;i=edge[i].next)
    {
        int t=edge[i].to;
        if(vis[t]) low[now]=min(low[now],dfn[t]);
        else if(!dfn[t]) tarjan1(t),low[now]=min(low[now],low[t]);
    }
    if(dfn[now]==low[now])
    {
        sum++; belong[now]=sum;ans[sum]++;
        for(;stack[top]!=now;top--)
         belong[stack[top]]=sum,vis[stack[top]]=false,ans[sum]++;
        vis[now]=false; top--;
    }
}
int begin()
{
    tot=,tim=,sum=,ans2=;
    memset(ans,,sizeof(ans));
    memset(dfn,,sizeof(dfn));
    memset(low,,sizeof(low));
    memset(vis,,sizeof(vis));
    memset(head,,sizeof(head));
    memset(belong,,sizeof(belong));
}
int main()
{
    )
    {
        m=read();) break;
        begin();cnt++,tot=;
        memset(cut_point,,sizeof(cut_point));
        ;i<=m;i++)
          x[i]=read(),y[i]=read(),add(x[i],y[i]),add(y[i],x[i]);
        tarjan(,); begin();
        ;i<=m;i++)
        {
            n=max(max(x[i],y[i]),n);
            if(cut_point[x[i]]||cut_point[y[i]]) continue;
            add(x[i],y[i]),add(y[i],x[i]);
        }
        ;i<=n;i++)
         if(!dfn[i]&&!cut_point[i]) tarjan1(i);
        ans1=sum;
        ;i<=sum;i++)
          ans2*=ans[i];
        printf("Case %d: %d %d\n",cnt,ans1,ans2);
    }
    ;
}

洛谷——P3225 [HNOI2012]矿场搭建的更多相关文章

  1. 洛谷 P3225 [HNOI2012]矿场搭建 解题报告

    P3225 [HNOI2012]矿场搭建 题目描述 煤矿工地可以看成是由隧道连接挖煤点组成的无向图.为安全起见,希望在工地发生事故时所有挖煤点的工人都能有一条出路逃到救援出口处.于是矿主决定在某些挖煤 ...

  2. 洛谷P3225 HNOI2012 矿场搭建

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

  3. 洛谷 P3225 [HNOI2012]矿场搭建

    传送门 题目大意:建设几个出口,使得图上无论哪个点被破坏,都可以与出口联通. 题解:tarjian求割点 首先出口不能建在割点上,找出割点,图就被分成了几个联通块. 每个联通块,建出口.如果割点数为0 ...

  4. 洛谷—— P3225 [HNOI2012]矿场搭建

    https://www.luogu.org/problem/show?pid=3225 题目描述 煤矿工地可以看成是由隧道连接挖煤点组成的无向图.为安全起见,希望在工地发生事故时所有挖煤点的工人都能有 ...

  5. BZOJ2730或洛谷3225 [HNOI2012]矿场搭建

    BZOJ原题链接 洛谷原题链接 显然在一个点双连通分量里,无论是哪一个挖煤点倒塌,其余挖煤点就可以互相到达,而对于一个点双连通分量来说,与外界的联系全看割点,所以我们先用\(tarjan\)求出点双连 ...

  6. P3225 [HNOI2012]矿场搭建 割点 tarjan 双联通分量

    https://www.luogu.org/problemnew/show/P3225 题意 煤矿工地可以看成是由隧道连接挖煤点组成的无向图.为安全起见,希望在工地发生事故时所有挖煤点的工人都能有一条 ...

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

    这道题挺难的,可以加深对割点的理解,还有,排列组合好重要了,分连通块,然后乘法原理(加法原理计数什么的) 传送门   https://www.luogu.org/problem/P3225 省选oi题 ...

  8. P3225 [HNOI2012]矿场搭建

    传送门 对于一个点双联通分量,如果它连接了两个或更多割点 那么不论哪个点GG都有至少一条路通到其他的点双联通分量,所以我们不用考虑 如果它只连接一个割点,如果这个割点GG,那整个块也一起GG,所以要再 ...

  9. [Luogu] P3225 [HNOI2012]矿场搭建

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

随机推荐

  1. 为sublime Text3 安装插件JS Format

    1. 安装package control 菜单 View - Show Console 或者 ctrl + ~ 快捷键,调出 console.将以下 Python 代码粘贴进去并 enter 执行,不 ...

  2. [译] 用win7自带工具找出svchost.exe的CPU使用率达到100%的元凶

    本文是我对自己上一篇转载的博客 <Figuring out why my SVCHOST.EXE is at 100% CPU without complicated tools in Wind ...

  3. Encryption requires the OpenSSL PHP extension 报错

    报错截图: 解决办法: 修改php.ini配置文件,打开该拓展 open php.ini search “opensll” remove the semicolon from: extension=p ...

  4. web前端中的一些注释表达法

    1.HTML注释 <!--注释的内容--> 注释的地方(根据个人习惯可能有所不同): 结束标签的后面,这一切都是为了程序在嵌套的时候更加方便.明了,如: <div class=&qu ...

  5. 将中文库导入到ARM板子中以解决中文显示乱码的教程

    1.将中文字符集导入到ARM板子中的/usr/fonts/目录下 在这里我们使用的字符集为:DroidSansFallback.ttf 下载地址为:https://pan.baidu.com/s/1e ...

  6. CodeForces - 1105D Kilani and the Game(多源BFS+暴力)

    题目: 给出一张游戏地图和每个玩家的位置,每次能移动的步数.p个玩家轮流移动占领地图中的格子(当格子已经被占领时就不能在占领了)在每个玩家都不能移动时游戏结束. 问在游戏结束后,每个玩家占领的格子的数 ...

  7. 如何使用MySQL一个表中的字段更新另一个表中字段

    [本文出自:https://www.jb51.net/article/150323.htm] 这篇文章主要介绍了如何使用MySQL一个表中的字段更新另一个表中字段,需要的朋友可以参考下 1,修改1列 ...

  8. 笔记本无法从DHCP服务器获取地址怎么解决?

    首先,开始/运行,输入 cmd,再输入ipconfig,看看你的IP地址是不是正常的,假如不是,就是获取不到IP地址.如果得到的IP是:169.254.x.x 表示客户机无法得到DHCP的响应.(如果 ...

  9. Java方法传递参数传值还是传址的问题

    这几天重构项目代码遇到一个疑问:可不可以在方法A中定义一个boolean变量b为false,然后A调用方法C把b传递到C方法中经过一些列业务判断后修改为true,C执行结束后A方法中b的值还是原来的f ...

  10. js layui 分页脚本

    //分页 layui.use(['laypage'], function(){ var laypage = layui.laypage; laypage.render({ elem: 'page' , ...