版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/pengwill97/article/details/81979635
题意
有一座地下的稀有金属矿由n条隧道和一些连接点组成,其中每条隧道连接两个连接点,任意两个连接点之间最多只有一条隧道。为了降低矿工的危险,你的任务是在一些连接点处安装太平井和相应的逃生装置,使得不管哪个连接点倒塌,不在此连接点的所有矿工都能到达太平井逃生(假定除了倒塌的连接点不能通行外,其他隧道和连接点完好无损)。为了节约成本,比应当在尽量少的连接点安装太平井。还需要计算出当太平井的数目最小时的总方案数。
题解
每个只有一个割点的bcc中,任选一个点即可。
为啥在只有一个割点的bcc中呢,考虑如下的情况。
1. 直接看样例的case2,其中1和2都是割点。当然我们知道割点都不选,所以这个是特殊情况,也就是在1和2组成的bcc中,我们都不选择。
2. 考虑上图的情况。图中2和5都是割点,于是有3个bcc,分别是1、2组成的bcc,2,、3、4、5组成的bcc和5、6组成的bcc。最佳选择是1和6分别选择。但是如果按照不是只有一个割点的bcc中任选一个,那么在中间的2、3、4、5组成的bcc中就会选出一个(因为他有两个割点)。这样显然不是最优的。
代码
#include<bits/stdc++.h>
using namespace std;
typedef double db;
typedef long long ll;
typedef unsigned long long ull;
const int nmax = 5e4+7;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
const ull p = 67;
const ull MOD = 1610612741;
int n, tot;
int head[nmax];
int dfn[nmax], low[nmax], dfs_clock, bcc_cnt, bccno[nmax], cut_cnt;
bool iscut[nmax];
struct edge{
int to, nxt;
}e[nmax <<1];
typedef pair<int, int> pii;
vector<int> bcc[nmax];
pii sstack[nmax];
int st;
void add_edge(int u, int v) {
e[tot].to = v;
e[tot].nxt = head[u];
head[u] = tot++;
}
void tarjan(int u, int fa) {
dfn[u] = low[u] = ++dfs_clock;
int child = 0;
for(int i = head[u]; i != -1; i = e[i].nxt) {
int v = e[i].to;
if(!dfn[v]) {
child ++;
sstack[st++] = make_pair(u, v);
tarjan(v, u);
low[u] = min(low[u], low[v]);
if(low[v] >= dfn[u]) {
iscut[u] = true;
cut_cnt ++;
bcc_cnt ++;
bcc[bcc_cnt].clear();
for(;;) {
pii tmp = sstack[--st];
if(bccno[tmp.first] != bcc_cnt) {
// if(iscut[tmp.first] == false)
bcc[bcc_cnt].push_back(tmp.first);
bccno[tmp.first] = bcc_cnt;
}
if(bccno[tmp.second] != bcc_cnt) {
// if(iscut[tmp.second] == false)
bcc[bcc_cnt].push_back(tmp.second);
bccno[tmp.second] = bcc_cnt;
}
if(tmp.first == u && tmp.second == v || tmp.first == v && tmp.second == u)
break;
}
}
} else if(v != fa && dfn[v] < dfn[u]) {
sstack[st++] = make_pair(u, v);
low[u] = min(low[u], dfn[v]);
}
}
if(fa == -1 && child <= 1) {
iscut[u] = false;
cut_cnt --;
}
}
int main(){
int kase = 1;
while(scanf("%d", &n) && n) {
memset(head, -1, sizeof head);
memset(dfn, 0, sizeof dfn);
memset(low ,0, sizeof low);
memset(iscut, 0, sizeof iscut);
memset(bccno, 0, sizeof bccno);
cut_cnt = bcc_cnt = st = dfs_clock = tot = 0;
int mx = 0;
for(int i = 1; i <= n; ++i) {
int u, v;
scanf("%d %d", &u, &v);
mx = max(mx , max(u, v));
add_edge(u, v);
add_edge(v, u);
}
for(int i = 1; i <= mx; ++i) {
if(!dfn[i])
tarjan(i, -1);
}
// for(int i = 1; i <= bcc_cnt; ++i) {
// printf("debug %d :", i);
// for(int j = 0; j < bcc[i].size(); ++j) {
// printf(" %d", bcc[i][j]);
// }
// printf("\n");
// }
printf("Case %d: ", kase ++);
ll ans = 1;
if(bcc_cnt == 1) {
ans = 1ll * mx * (mx-1) / 2;
printf("%d %lld\n", 2, ans);
} else {
int cnt = 0;
for(int i = 1; i <= bcc_cnt; ++i) {
int cut_num = 0;
for(int j = 0; j < bcc[i].size(); ++j) {
if(iscut[bcc[i][j]])
cut_num ++;
}
if(cut_num == 1) {
cnt ++;
ans = ans * ( 1ll * (bcc[i].size() - cut_num) );
}
}
printf("%d %lld\n", cnt, ans);
}
}
return 0;
}