2730: [HNOI2012]矿场搭建

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 3230  Solved: 1540
[Submit][Status][Discuss]

Description

煤矿工地可以看成是由隧道连接挖煤点组成的无向图。为安全起见,希望在工地发生事故时所有挖煤点的工人都能有一条出路逃到救援出口处。于是矿主决定在某些挖煤点设立救援出口,使得无论哪一个挖煤点坍塌之后,其他挖煤点的工人都有一条道路通向救援出口。请写一个程序,用来计算至少需要设置几个救援出口,以及不同最少救援出口的设置方案总数。

Input

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

Output

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

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

HINT

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

Solution

可以发现要找的特殊点的数量和图中割点有关。因为割点会把一个联通块分离成几块,导致中间断开,此时肯定需要增加安放的特殊点。

当把割点删去后分离成多个点双联通分量。

此时对每个点双进行讨论:

如果点双中与0个割点相邻,那么需要在点双中新增两个特殊点,防止其中一个特殊点挂了。

如果点双中与1个割点相邻,那么需要在点双中新增一个特殊点,为这个割点提供备用。

如果点双中与2个割点相邻,那么不需要增加特殊点,一个割点挂了可以走另一个割点离开。

然后就可以用乘法原理算出方案数了。

Code

  1. #include<bits/stdc++.h>
  2. #define LL long long
  3. using namespace std;
  4.  
  5. int n, m;
  6.  
  7. struct Node {
  8. int u, v, nex;
  9. } Edge[];
  10.  
  11. int stot, h[];
  12. void add(int u, int v) {
  13. Edge[++stot] = (Node) {u, v, h[u]};
  14. h[u] = stot;
  15. }
  16.  
  17. int dfn[], low[], idc, stk[], tp, cut[];
  18. void Tarjan(int u, int fa) {
  19. dfn[u] = low[u] = ++ idc;
  20. stk[++tp] = u;
  21. int son = ;
  22. for(int i = h[u]; i; i = Edge[i].nex) {
  23. int v = Edge[i].v;
  24. if(i == (fa ^ )) continue;
  25. if(!dfn[v]) {
  26. son ++;
  27. Tarjan(v, i);
  28. low[u] = min(low[u], low[v]);
  29. if(low[v] >= dfn[u]) cut[u] = ;
  30. } else low[u] = min(low[u], dfn[v]);
  31. }
  32. if(fa == && son == ) cut[u] = ;
  33. }
  34.  
  35. int siz, cut_num, cnt, color[];
  36. void dfs(int u) {
  37. color[u] = cnt;
  38. if(cut[u]) return ;
  39. siz ++;
  40. for(int i = h[u]; i; i = Edge[i].nex) {
  41. int v = Edge[i].v;
  42. if(cut[v] && color[v] != cnt) {
  43. cut_num ++; color[v] = cnt;
  44. }
  45. if(!color[v]) dfs(v);
  46. }
  47. }
  48.  
  49. int main() {
  50. int ti = ;
  51. while(~scanf("%d", &m)) {
  52. if(m == ) break;
  53. n = ;
  54. stot = ; memset(h, , sizeof(h));
  55. cnt = ; tp = ; idc = ;
  56. memset(dfn, , sizeof(dfn));
  57. memset(low, , sizeof(low));
  58. memset(color, , sizeof(color));
  59. memset(cut, , sizeof(cut));
  60. for(int i = ; i <= m; i ++) {
  61. int u, v;
  62. scanf("%d%d", &u, &v);
  63. add(u, v); add(v, u);
  64. n = max(max(n, v), u);
  65. }
  66. for(int i = ; i <= n; i ++) if(!dfn[i]) Tarjan(i, );
  67. LL ans1 = , ans2 = ;
  68. for(int i = ; i <= n; i ++) {
  69. if(!cut[i] && !color[i]) {
  70. cnt ++; siz = , cut_num = ; dfs(i);
  71. if(cut_num == ) { ans1 += ; ans2 *= 1ll * (siz - ) * siz / ;}
  72. if(cut_num == ) { ans1 += ; ans2 *= siz;}
  73. }
  74. }
  75. printf("Case %d: %lld %lld\n", ++ti, ans1, ans2);
  76. }
  77. return ;
  78. }

【BZOJ】2730: [HNOI2012]矿场搭建【Tarjan找割点】【分联通块割点个数】的更多相关文章

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

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

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

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

  3. bzoj 2730: [HNOI2012]矿场搭建【tarjan】

    先tarjan找割点和点双连通分量,然后对一个点双,如果没有割点,那么需要建立两个出口(割掉一个另一个备用):如果只有一个割点,出口可以设立在任意一个非割点的地方:如果有两个及以上个割点,就不用建出口 ...

  4. 【刷题】BZOJ 2730 [HNOI2012]矿场搭建

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

  5. bzoj 2730: [HNOI2012]矿场搭建

    #include<cstdio> #include<cstring> #include<iostream> #define M 508 using namespac ...

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

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

  7. 【BZOJ2730】[HNOI2012] 矿场搭建(找割点)

    点此看题面 大致题意: 一张无向图,要求你在去掉任意一个节点之后,剩余的每个节点都能到达一个救援出口,问至少需要几个救援出口. 第一步:\(Tarjan\)求割点 首先,我们要跑一遍\(Tarjan\ ...

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

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

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

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

随机推荐

  1. socket相关系统调用的调用流程

    最近一直在读内核网络协议栈源码,这里以ipv4/tcp为例对socket相关系统调用的流程做一个简要整理,这些相关系统调用的内部细节虽然各有不同,但其调用流程则基本一致: 调用流程: (1)系统调用 ...

  2. Linux内核触摸屏驱动--多点触摸 【转】

      转自:http://blog.chinaunix.net/uid-24227137-id-3127126.html 简介 为了使用功能强大的多点触控设备,就需要一种方案去上报用户层所需的详细的手指 ...

  3. Android性能测试工具之APT

    1.APT工具简介: APT是一个eclipse插件,可以实时监控Android手机上多个应用的CPU.内存数据曲线,并保存数据:另外还支持自动获取内存快照.PMAP文件分析等,方便开发人员自测或者测 ...

  4. 监听 手机back键和顶部的回退

    // 回退事件,监听 手机back键和顶部的回退 pushHistory(); window.addEventListener("popstate", function(e) { ...

  5. GBDT+LR simple例子

    卧槽,本来猜GBDT获取的组合特征,需要自己去解析GBDT的树,scikit learn里面竟然直接调用apply函数就可以了 # 弱分类器的数目 n_estimator = 10 # 随机生成分类数 ...

  6. 制作macOS10.12系列的系统镜像文件

    制作macOS10.12系列的系统镜像文件步骤,过程也比较简单,十来个命令.以10.12.6为例,首先,在苹果商店下载系统安装包APP,或者网上下载后把安装APP复制到  应用程序  文件夹. 然后打 ...

  7. 20165203《Java程序设计》第三周学习总结

    教材学习内容总结 1.类: (1)类的声明:class+类名 (2)类体:成员变量的声明+方法(局部变量+语句) 注意: 方法体内声明的局部变量只在方法内有效和书写位置有关. 局部变量和成员变量同名: ...

  8. 函数fgets和fputs、fread和fwrite用法小结(转)

    字符串读写函数fgets和fputs: 1.fgets()函数:原型char *fgets(char *s, int n, FILE *stream);从流中读取n-1(n默认1024)个字符之前,如 ...

  9. Asp.net Vnext TagHelpers

    概述 本文已经同步到<Asp.net Vnext 系列教程 >中] TagHelpers 是vnext中引入的新功能之一.TagHelper 的作用是类似于发挥在以前版本的 ASP.NET ...

  10. USACO 6.2 Packing Rectangles

    Packing RectanglesIOI 95 The six basic layouts of four rectangles Four rectangles are given. Find th ...