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

先tarjan求出割点.. 

割点把图分成了几个双连通分量..只需dfs找出即可. 然后一个bcc有>2个割点, 那么这个bcc就不用建了, 因为一定可以走到其他救援出口. 只有一个割点的bcc就要建, bcc内任何一个非割点的结点都可以建. dfs的时候记一下bcc的结点数, 然后乘法原理算出方案数.再特判整个图为一个bcc的情况。

-------------------------------------------------------------------------------------

#include<bits/stdc++.h>
 
using namespace std;
 
const int maxn = 509;
 
struct edge {
int to;
edge* next;
} E[maxn << 1], *pt = E, *head[maxn];
 
inline void add(int u, int v) {
pt->to = v; pt->next = head[u]; head[u] = pt++;
}
inline void addedge(int u, int v) {
add(u, v); add(v, u);
}
 
int N, dfn[maxn], low[maxn], bcc[maxn], cnt[maxn], size[maxn], CK, n;
bool cut[maxn], vis[maxn];
 
void init() {
N = n = CK = 0;
memset(dfn, 0, sizeof dfn);
memset(low, 0, sizeof low);
memset(bcc, 0, sizeof bcc);
memset(cut, 0, sizeof cut);
memset(cnt, 0, sizeof cnt);
memset(vis, 0, sizeof vis);
memset(size, 0, sizeof size);
memset(head, 0, sizeof head);
}
 
void tarjan(int x, int fa = -1) {
dfn[x] = low[x] = ++CK;
int ch = 0;
for(edge* e = head[x]; e; e = e->next) {
if(!dfn[e->to]) {
ch++;
tarjan(e->to, x);
if(low[e->to] >= dfn[x]) 
cut[x] = true;
else
low[x] = min(low[x], low[e->to]);
} else if(dfn[e->to] < dfn[x] && e->to != fa)
low[x] = min(low[x], dfn[e->to]);
}
if(fa < 0 && ch == 1) cut[x] = false;
}
 
void dfs(int x) {
vis[x] = true;
for(edge* e = head[x]; e; e = e->next) if(!vis[e->to]) {
if(!cut[e->to]) dfs(e->to);
else if(bcc[e->to] != n) cnt[bcc[e->to] = n]++;
}
size[bcc[x] = n]++;
}
 
int main() {
int m, T = 0;
while(scanf("%d", &m) == 1 && m) {
init();
while(m--) {
int u, v;
scanf("%d%d", &u, &v);
if(N < u) N = u;
if(N < v) N = v;
addedge(--u, --v);
}
for(int i = 0; i < N; i++) if(!dfn[i]) tarjan(i);
for(int i = 0; i < N; i++)
if(!cut[i] && !vis[i]) n++, dfs(i);
int ans0 = 0;
long long ans = 1;
for(int i = 1; i <= n; i++)
if(cnt[i] == 1) ans *= size[i], ans0++;
if(n == 1)
ans0 = 2, ans = N * (N - 1) >> 1;
printf("Case %d: %d %lld\n", ++T, ans0, ans);
}
return 0;
}

-------------------------------------------------------------------------------------

2730: [HNOI2012]矿场搭建

Time Limit: 10 Sec   Memory Limit: 128 MB
Submit: 1084   Solved: 503
[ Submit][ Status][ Discuss]

Description

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

Input

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

Output

输入文件中有多少组数据,输出文件 output.txt 中就有多少行。每行对应一组输入数据的 结果。其中第 i 行以 Case i: 开始(注意大小写,Case  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)

Source

 

转载于:https://www.cnblogs.com/JSZX11556/p/4851736.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值