Solution

输入中没有出现过的矿场点是不用考虑的, 所以不用考虑只有 一个点 的点双联通分量。

要使某个挖矿点倒塌, 相当于割去这个点, 所以我们求一遍割点和点双联通分量。

之后的点双联通分量构成一棵树。 树上的节点有两种情况

1: 仅有一条边(仅有 一个割点 在内部)—— 相当与叶子节点, 把它与父亲节点相连的割点割去后,必须在里面设一个逃生出口

2: 大于一条边(有大于一个割点在内部 )——割去其中一个割点时, 还可以通过另一个割点到达逃生出口, 所以不用设置。

所以我们要求的就是在所有 仅含一个割点的 点双联通分量 内设置 一个 逃生出口, 并根据 乘法原理 计算方案数。

特别的: 当整个图是一个 点双连通图时, 设置任意 两个 逃生出口即可。

Code

 #include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
#define rd read()
#define R register
#define ll long long
using namespace std; const int N = 1e3; int head[N], tot;
int dfn[N], low[N], col_num;//col_num为点双联通分量个数
int n, m, mark[N], cut[N], rt, maxn, cut_num[N];//cut_num为点双联通分量内的割点数
int st[N], tp, cnt;
ll ans1, ans2; vector<int> q[N];
struct edge {
int nxt, to, fr;
}e[N << ]; int read() {
int X = , p = ; char c = getchar();
for(; c > '' || c < ''; c = getchar()) if(c == '-') p = -;
for(; c >= '' && c <= ''; c = getchar()) X = X * + c - '';
return X * p;
} void add(int u, int v) {
e[++tot].to = v;
e[tot].nxt = head[u];
e[tot].fr = u;
head[u] = tot;
} void tarjan(int u) {
dfn[u] = low[u] = ++cnt;
st[++tp] = u;
int flag = ;
for(R int i = head[u]; i; i = e[i].nxt) {
R int nt = e[i].to;
if(!dfn[nt]) {
tarjan(nt);
low[u] = min(low[u], low[nt]);
if(low[nt] >= dfn[u]) {
col_num++;
flag ++;
if(flag > || u != rt)
cut[u] = ;
for(; tp;) {
int z = st[tp--];
q[col_num].push_back(z);
if(z == nt) break;
}
q[col_num].push_back(u);
}
} else low[u] = min(low[u], dfn[nt]);
}
} void init() {
for(int i = ; i <= col_num; ++i)
q[i].clear();
ans1 = maxn = col_num = cnt = tot = ;
ans2 = ;
memset(dfn, , sizeof(dfn));
memset(mark, , sizeof(mark));
memset(cut, , sizeof(cut));
memset(low, , sizeof(low));
memset(head, , sizeof(head));
memset(cut_num, , sizeof(cut_num));
} int main()
{
for(int T = ; ; T++) {
n = rd;
if(!n) return ;
init();
for(int i = ; i <= n; ++i) {
int u = rd, v = rd;
add(u, v); add(v, u);
mark[u] = mark[v] = ;
maxn = max(maxn, u);
maxn = max(maxn, v);
}
for(int i = ; i <= maxn; ++i)
if(!dfn[i] && mark[i]) tarjan(rt = i);
for(int i = ; i <= col_num; ++i)
for(int j = , len = q[i].size(); j < len; ++j) {
if(cut[q[i][j]]) cut_num[i]++;
}
for(int i = ; i <= col_num; ++i)
if(cut_num[i] == ) ans1++, ans2 = ans2 * (int)(q[i].size() - );
printf("Case %d: %lld %lld\n", T, ans1 ? ans1 : , ans1 ? ans2 : (int)(q[].size() - ) * q[].size()/ );
}
}

BZOJ2730 [HNOI2012]矿场搭建 - Tarjan割点的更多相关文章

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

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

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

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

  3. [BZOJ2730][HNOI2012]矿场搭建 点双 割点

    2730: [HNOI2012]矿场搭建 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 2852  Solved: 1344[Submit][Stat ...

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

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

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

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

  6. BZOJ 2730:[HNOI2012]矿场搭建(割点+连通块)

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

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

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

  8. bzoj2730 [HNOI2012]矿场搭建 (UVAlive5135 Mining Your Own Business)

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

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

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

随机推荐

  1. 设置HTML编码为UTF-8

    <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content ...

  2. 微信小程序--分享报错(thirdScriptError Cannot read property 'from' of undefined;at pages/index/index page onShareAppMessage function TypeError: Cannot read property 'from' of undefined)

    分享功能: onShareAppMessage: function (res) { if (res.from === 'button') { // 来自页面内转发按钮 console.log(res. ...

  3. 了解一些dos常用命令

    备注:[] ——可选项   <>——必填项 DOS 特殊命令应用技巧: 向上箭头“↑”和向下箭头“↓”——回看上一次执行的命令 "Ctrl+C"组合——中断操作 在命令 ...

  4. Eclipse 合并GIT分支

    合并GIT分支: 1.  切换到主分支: 2.  右击项目——Team——Merge…: 3.  在弹出的Merge框中选择要合并的分支——Merge: 4.  合并后如果出现冲突,右击项目——Tea ...

  5. OnContextMenu实现禁止鼠标右键

    OnContextMenu事件 定义和使用:oncontextmenu 事件在元素中用户右击鼠标时触发并打开上下文菜单.注意:所有浏览器都支持 oncontextmenu 事件, contextmen ...

  6. PropertyGrid控件动态生成属性及下拉菜单 (转)

    http://blog.sina.com.cn/s/blog_6f14b7010101b91b.html https://msdn.microsoft.com/zh-cn/library/ms1718 ...

  7. java面试题:分布式

    分布式分为分布式缓存(Redis).分布式锁(Redis或Zookeeper).分布式服务(Dubbo或SpringCloud).分布式服务协调(Zookeeper).分布式消息队列(Kafka.Ra ...

  8. as3.0 橡皮功能2

    package com{ import flash.display.MovieClip; import flash.display.Bitmap; import flash.display.Bitma ...

  9. white-space和word-wrap和word-break所表示的换行和不换行的区别

    一.前言 使得文本换行有很多方式, <br/>标签元素,能够强制使得所在位置文本换行 <p>元素,<div>设定宽度,都可以对文本内容实现自适应换行 对于长单词或者 ...

  10. ES6之Promise对象

    创建Promise对象 function getHtml(url) { return new Promise((resolve, reject) => { let xhr = new XMLHt ...