题目

Description

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

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

Input

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

Output

输入文件中有多少组数据,输出文件中就有多少行。每行对应一组输入数据的结果。

其中第 i 行以 Case i: 开始(注意大小写,Case 与 i 之间有空格,i 与 : 之间无空格,: 之后有空格),其后是用空格隔开的两个正整数,第一个正整数表示对于第 i组输入数据至少需要设置几个救援出口,第二个正整数表示对于第 i 组输入数据不同最少救援出口的设置方案总数。

输出格式参照以下输入输出样例。

题解

再点双连通分量中,如果坏了其中一个点,那么剩下的点还是连通的,所以我们求一次点双连通分量,再仔细观察一下,如果一个点双中(非割点点数为 \(n\)):

  1. 没有割点,那么显然要两个通道,共 \(C_n^2\) 种选法。
  2. 有一个割点,那么在这个点双中就要有一个通道,共,有一个割点,那么在这个点双中就要有一个通道,共 \(n\) 种选法。
  3. 有两个或者两个以上的割点,则不需要通道。

问题解决了,不过我可能是太弱了,统计割点数和非割点数写挂了,我们其实可以把每个割点找出来,dfs 一遍,割点之间就是一个点双,另外相邻的割点也属于这个点双。

CODE

#include<iostream>
#include<stack>
#include<cstring>
#include<cstdio>
using namespace std; int dfn[10005],low[10005],cp[10005],cnt=0;
int bcc[10005],num[10005],son[10005],C=0;
bool vis[100005],iscp[100005];
int n,m,x,y,h[100005],tot=0,cas=0;
struct Edge{
int x,next;
}e[200005]; inline void add_edge(int x,int y){
e[++tot].x=y;
e[tot].next=h[x],h[x]=tot;
} stack<int> s; void tarjan(int x,int fa){
low[x]=dfn[x]=++cnt;
son[x]=0;
for(int i=h[x];i;i=e[i].next){
if(e[i].x==fa)continue;
if(!dfn[e[i].x]){
tarjan(e[i].x,x),son[x]++;
low[x]=min(low[x],low[e[i].x]);
if(low[e[i].x]>=dfn[x]&&fa!=0)iscp[x]=true;
}
else low[x]=min(low[x],dfn[e[i].x]);
}
if(son[x]>1&&fa==0)iscp[x]=true;
} void dfs(int x){
vis[x]=true,num[C]++;
for(int i=h[x];i;i=e[i].next){
if(vis[e[i].x])continue;
if(!iscp[e[i].x])dfs(e[i].x);
else{
if(bcc[e[i].x]!=C)
bcc[e[i].x]=C,cp[C]++;
}
}
} int main(){
while(scanf("%d",&m),m){
memset(h,0,sizeof(h));
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
memset(bcc,0,sizeof(bcc));
memset(num,0,sizeof(num));
memset(cp,0,sizeof(cp));
memset(iscp,0,sizeof(iscp));
memset(vis,0,sizeof(vis));
tot=cnt=C=n=0;
for(int i=1;i<=m;i++){
scanf("%d%d",&x,&y);
add_edge(x,y);
add_edge(y,x);
n=max(n,max(x,y));
}
for(int i=1;i<=n;i++)
if(!dfn[i])tarjan(i,0);
unsigned long long sum=0,ans=1;
for(int i=1;i<=n;i++){
if(!iscp[i]&&!vis[i]){
C++,dfs(i);
if(cp[C]==1)sum++,ans*=num[C];
}
}
if(C==1)sum=2,ans=n*(n-1)/2;
printf("Case %d: ",++cas);
printf("%llu %llu\n",sum,ans);
}
}

[HNOI2012]矿场搭建(tarjan求点双)的更多相关文章

  1. bzoj 2730: [HNOI2012]矿场搭建——tarjan求点双

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

  2. BZOJ 2730: [HNOI2012]矿场搭建( tarjan )

    先tarjan求出割点.. 割点把图分成了几个双连通分量..只需dfs找出即可. 然后一个bcc有>2个割点, 那么这个bcc就不用建了, 因为一定可以走到其他救援出口. 只有一个割点的bcc就 ...

  3. 【BZOJ2730】[HNOI2012]矿场搭建 Tarjan

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

  4. BZOJ 2730 矿场搭建 Tarjan求割点

    思路: Tarjan求出来点双&割点 判一判就行了 //By SiriusRen #include <stack> #include <cstdio> #include ...

  5. BZOJ2730 [HNOI2012]矿场搭建 - Tarjan割点

    Solution 输入中没有出现过的矿场点是不用考虑的, 所以不用考虑只有 一个点 的点双联通分量. 要使某个挖矿点倒塌, 相当于割去这个点, 所以我们求一遍割点和点双联通分量. 之后的点双联通分量构 ...

  6. P3225 [HNOI2012]矿场搭建 tarjan割点

    这个题需要发现一点规律,就是先按割点求块,然后求每个联通块中有几个割点,假如没有割点,则需要建两个出口,如果一个割点,则需要建一个出口,2个以上不用建. 题干: 题目描述 煤矿工地可以看成是由隧道连接 ...

  7. [BZOJ2730][HNOI2012]矿场搭建(求割点)

    题目:http://www.lydsy.com:808/JudgeOnline/problem.php?id=2730 分析: 如果坍塌的点不是割点,那没什么影响,主要考虑坍塌的点是割点的情况. 显然 ...

  8. C++[Tarjan求点双连通分量,割点][HNOI2012]矿场搭建

    最近在学图论相关的内容,阅读这篇博客的前提是你已经基本了解了Tarjan求点双. 由割点的定义(删去这个点就可使这个图不连通)我们可以知道,坍塌的挖煤点只有在割点上才会使这个图不连通,而除了割点的其他 ...

  9. Tarjan 点双+割点+DFS【洛谷P3225】 [HNOI2012]矿场搭建

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

  10. 【BZOJ-2730】矿场搭建 Tarjan 双连通分量

    2730: [HNOI2012]矿场搭建 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1602  Solved: 751[Submit][Statu ...

随机推荐

  1. Steamroller-freecodecamp算法题目

    Steamroller 1.要求 对嵌套的数组进行扁平化处理.你必须考虑到不同层级的嵌套. 2.思路 设定结果数组res 用for循环遍历arr的元素,判断是否为数组,是,则用res=res.conc ...

  2. 2018.11.3 Nescafe18 T1 七夕祭

    题目 背景 七夕节因牛郎织女的传说而被扣上了「情人节」的帽子.于是 TYVJ 今年举办了一次线下七夕祭.Vani 同学今年成功邀请到了 cl 同学陪他来共度七夕,于是他们决定去 TYVJ七夕祭游玩. ...

  3. 第2 章Python 语言基础

    必背必记 1.转义字符   Python 中的字符串还支持转义字符.所谓转义字符是指使用反斜杠“\”对一些特殊字符进行转义. \ 续行符 \n 换行符 \0 空 \t 水平制表符,用于横向跳到下一制表 ...

  4. 动态拼接SQL语句

    1.参考官方文档 ? if:字符判断 ? choose (when, otherwise):分支选择 ? trim (where, set):字符串截取:其中where标签封装查询条件,set标签封装 ...

  5. HDU - 5017 Ellipsoid(模拟退火)

    题意 给一个三维椭球面,求球面上距离原点最近的点.输出这个距离. 题解 模拟退火. 把\(z = f(x, y)\)函数写出来,这样通过随机抖动\(x\)和\(y\)坐标就能求出\(z\). 代码 / ...

  6. Java文件 ---流

    分类 根据数据走向,分为输入流.输出流 根据处理的数据类型,分为字节流.字符流 字节流 可以处理所有类型的数据,如MP3.图片.文字.视频等.在读取时,读到一个字节就返回一个字节. 在Java中对应的 ...

  7. js 实现5秒倒计时后跳转页面

    <script type="text/javascript"> function countDown(secs, surl) { var jumpTo = docume ...

  8. 程序集链接器(AL.exe)

    AL.exe使用程序可以生成一个EXE文件或者DLL PE文件(其中只包含对其他模块中的类型进行描述的一个清单). 不要在普通的命令行窗口中编译,请先打开C:\ProgramData\Microsof ...

  9. Marketing learning-1

    Today we start to learn something about marketing together.Sometimes i just propose a question,and i ...

  10. 如何将Linux rm命令删除的文件放入垃圾箱

    因为rm命令删除的文件是不会放入垃圾箱的,所以无法恢复,下面小编就给大家介绍一种方法,通过替换Linux rm命令的方法,从而将rm命令删除的文件放入垃圾箱. 方法: 1. 在/home/userna ...