Bzoj2730 [HNOI2012]矿场搭建

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 1667  Solved: 787

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)。

Source

 
点双连通分量。
只有图上的割点坍塌的时候,才会有人被困住。
tarjan找出所有的割点,之后统计只连接着一个割点的联通块(如果联通块连着两个割点,一个没了还能从另一个到别处),答案累乘符合条件的联通块的点数。
 
↑输入数据读入的是边数,傻傻当成了点数,读入错了,还一直查算法的问题……
↑WA到飞起以后怒看题解,代码改得和Tunix的基本一样了,才发现读入……(望天)
 
 1 /*by SilverN*/
 2 #include<algorithm>
 3 #include<iostream>
 4 #include<cstring>
 5 #include<cstdio>
 6 #include<cmath>
 7 #include<vector>
 8 #define LL unsigned long long
 9 using namespace std;
10 const int mxn=100010;
11 int read(){
12     int x=0,f=1;char ch=getchar();
13     while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
14     while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
15     return x*f;
16 }
17 struct edge{
18     int v,nxt;
19 }e[mxn];
20 int hd[mxn],mct=0;
21 void add_edge(int u,int v){
22     e[++mct].v=v;e[mct].nxt=hd[u];hd[u]=mct;
23     return;
24 }
25 int dfn[mxn],low[mxn],dtime;
26 int bct=0;
27 bool cut[mxn];
28 void DFS(int u,int fa){
29     dfn[u]=low[u]=++dtime;
30     int child=0;
31     for(int i=hd[u];i;i=e[i].nxt){
32         int v=e[i].v;
33         if(v==fa)continue;
34         if(!dfn[v]){
35             child++;
36             DFS(v,u);
37             low[u]=min(low[u],low[v]);
38             if(dfn[u]<=low[v]) cut[u]=1;
39         }
40         else low[u]=min(low[u],dfn[v]);
41     }
42     if(!fa && child==1)cut[u]=0;
43     return;
44 }
45 bool vis[mxn];int num[mxn],belone[mxn],have[mxn];
46 void solve(int u){
47     vis[u]=1;num[bct]++;
48     for(int i=hd[u];i;i=e[i].nxt){
49         int v=e[i].v;
50         if(!vis[v]){
51             if(!cut[v])solve(v);
52             else if(belone[v]!=bct){
53                     belone[v]=bct;
54                     have[bct]++;
55             }
56         }
57     }
58     return;
59 }
60 int n,m;
61 LL ans=0;
62 void init(){
63     memset(dfn,0,sizeof dfn);
64     memset(low,0,sizeof low);
65     memset(hd,0,sizeof hd);
66     memset(cut,0,sizeof cut);
67     memset(num,0,sizeof num);
68     memset(vis,0,sizeof vis);
69     memset(have,0,sizeof have);
70     mct=0;ans=1;bct=0;dtime=0;n=0;
71 }
72 int main(){
73     int i,j,u,v;
74     int cas=0;
75     while(scanf("%d",&m) && m){
76         init();
77         for(i=1;i<=m;i++){
78             u=read();v=read();
79             n=max(n,max(u,v));
80             add_edge(u,v);
81             add_edge(v,u);
82         }
83         for(i=1;i<=n;i++)if(!dfn[i])DFS(i,0);
84         int res=0;
85         for(i=1;i<=n;i++){
86             if(!vis[i] && !cut[i]){
87                 bct++;
88                 solve(i);
89                 if(have[bct]==1) res++,ans*=num[bct];
90             }
91         }
92         if(bct==1)res=2,ans=(LL)n*(n-1)/2;
93         printf("Case %d: ",++cas);
94         printf("%d ",res);
95         printf("%llu
",ans);
96     }
97     return 0;
98 }
原文地址:https://www.cnblogs.com/SilverNebula/p/6050416.html