【BZOJ 2730】 [HNOI2012]矿场搭建
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
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
Case 2: 4 1
HINT
Case 1 的四组解分别是(2,4),(3,4),(4,5),(4,6);
Case 2 的一组解为(4,5,6,7)。
寻找图上的割点
不要在割点建安全点
如果图上没有割点则答案为C(n,2)
删掉割点跑联通性
如果一个联通块内有两个及以上割点就不用建,塌了一个还可以跑去别的地方
有一个割点就要建一个,不要建在割点
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 using namespace std; 5 const int N=510; 6 struct ee{int to,next;}e[N*N]; 7 int head[N],dfn[N],low[N],size[N],sum[N]; 8 bool cut[N],vis[N],vis1[N]; 9 int cnt,n,sz,T,m,timer; 10 long long num,ans; 11 void ins(int u,int v){ 12 e[++cnt].to=v,e[cnt].next=head[u],head[u]=cnt; 13 e[++cnt].to=u,e[cnt].next=head[v],head[v]=cnt; 14 } 15 int tarjan(int u,int fa){ 16 int child=0,lowu; 17 lowu=dfn[u]=low[u]=++timer; 18 for (int i=head[u];i;i=e[i].next){ 19 int v=e[i].to; 20 if(!dfn[v]){ 21 child++; 22 int lowv=tarjan(v,u); 23 lowu=min(lowu,lowv); 24 if (lowv>=dfn[u]) cut[u]=1; 25 } 26 else if(dfn[v]<dfn[u]&&v!=fa) 27 lowu=min(lowu,dfn[v]); 28 } 29 if(fa<0&&child==1) cut[u]=0; 30 low[u]=lowu; 31 return lowu; 32 } 33 34 void dfs(int x,int sz){ 35 vis[x]=1;size[sz]++; 36 for (int i=head[x];i;i=e[i].next){ 37 int v=e[i].to; 38 if(!vis[v]&&!cut[v]){ 39 dfs(v,sz); 40 }else{ 41 if (cut[v]&&!vis1[v]) sum[sz]++,vis1[v]=1; 42 } 43 } 44 } 45 46 int main(){ 47 while(1){ 48 scanf("%d",&m); 49 if(m==0) break; 50 cnt=n=sz=timer=num=0;ans=1; 51 memset(head,0,sizeof(head)); 52 memset(e,0,sizeof(e)); 53 memset(cut,0,sizeof(cut)); 54 memset(vis,0,sizeof(vis)); 55 memset(low,0,sizeof(low)); 56 memset(dfn,0,sizeof(dfn)); 57 memset(sum,0,sizeof(sum)); 58 memset(size,0,sizeof(size)); 59 T++;printf("Case %d: ",T); 60 int u,v; 61 for(int i=1;i<=m;i++){ 62 scanf("%d%d",&u,&v); 63 n=max(n,u),n=max(n,v); 64 ins(u,v); 65 } 66 tarjan(1,-1); 67 for(int i=1;i<=n;i++) if(!cut[i]&&!vis[i]) { 68 memset(vis1,0,sizeof(vis1)); 69 dfs(i,++sz); 70 } 71 if(sz==1) ans=(n-1)*n/2,num=2; 72 else{ 73 for (int i=1;i<=sz;i++){ 74 if(sum[i]==1)ans*=size[i],num++; 75 } 76 } 77 printf("%lld %lld\n",num,ans); 78 } 79 }