[HNOI2012]矿场搭建
题目描述
煤矿工地可以看成是由隧道连接挖煤点组成的无向图。为安全起见,希望在工地发生事故时所有挖煤点的工人都能有一条出路逃到救援出口处。于是矿主决定在某些挖煤点设立救援出口,使得无论哪一个挖煤点坍塌之后,其他挖煤点的工人都有一条道路通向救援出口。
请写一个程序,用来计算至少需要设置几个救援出口,以及不同最少救援出口的设置方案总数。
输入输出格式
输入格式:
输入文件有若干组数据,每组数据的第一行是一个正整数 N(N<=500),表示工地的隧道数,接下来的 N 行每行是用空格隔开的两个整数 S 和 T,表示挖 S 与挖煤点 T 由隧道直接连接。输入数据以 0 结尾。
输出格式:
输入文件中有多少组数据,输出文件 output.txt 中就有多少行。每行对应一组输入数据的 结果。其中第 i 行以 Case i: 开始(注意大小写,Case 与 i 之间有空格,i 与:之间无空格,: 之后有空格),其后是用空格隔开的两个正整数,第一个正整数表示对于第 i 组输入数据至少需 要设置几个救援出口,第二个正整数表示对于第 i 组输入数据不同最少救援出口的设置方案总 数。输入数据保证答案小于 2^64。输出格式参照以下输入输出样例。
输入输出样例
说明
Case 1 的四组解分别是(2,4),(3,4),(4,5),(4,6);
Case 2 的一组解为(4,5,6,7)。
分析:
本题首先求出连通块个数,然后再求出每个连通块中割点个数,最后再分类讨论即可。
CODE:
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 #define ll long long 6 #define maxn 510 7 using namespace std; 8 int n,m,num,head[maxn],topt,c[maxn],r[maxn],matc[maxn],ans,cas; 9 int f[maxn],low[maxn],dfn[maxn],sum,size[maxn]; 10 ll cnt; 11 struct node{ 12 int v,pre; 13 }e[maxn*maxn]; 14 int init(){ 15 int x=0,f=1;char s=getchar(); 16 while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();} 17 while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();} 18 return x*f; 19 } 20 void Add(int from,int to){ 21 e[num].v=to; 22 e[num].pre=head[from]; 23 head[from]=num++; 24 } 25 void Cl(){ 26 ans=0;cnt=1;topt=0;sum=0;num=0;n=0; 27 memset(head,-1,sizeof(head)); 28 memset(size,0,sizeof(size)); 29 memset(dfn,0,sizeof(dfn)); 30 memset(low,0,sizeof(low)); 31 memset(matc,0,sizeof(matc)); 32 memset(f,0,sizeof(f)); 33 memset(r,0,sizeof(r)); 34 memset(c,0,sizeof(c)); 35 } 36 void Dfs(int u,int from){ 37 dfn[u]=low[u]=++topt;int x=0; 38 for(int i=head[u];i!=-1;i=e[i].pre){ 39 int v=e[i].v; 40 if((i^1)==from)continue; 41 if(!dfn[v]){ 42 x++;Dfs(v,i);low[u]=min(low[u],low[v]); 43 if(low[v]>=dfn[u])c[u]=1; 44 } 45 else low[u]=min(low[u],dfn[v]); 46 } 47 if(from<0&&x==1)c[u]=0; 48 } 49 void dfs(int x){ 50 f[x]=1;size[sum]++; 51 for(int i=head[x];i!=-1;i=e[i].pre){ 52 int v=e[i].v; 53 if(f[v])continue; 54 if(c[v]==0)dfs(v); 55 else if(matc[v]!=sum){ 56 matc[v]=sum;r[sum]++; 57 } 58 } 59 } 60 int main() 61 { 62 while(1){ 63 m=init();int u,v; 64 if(m==0)break;Cl(); 65 while(m--){ 66 u=init();v=init(); 67 Add(u,v);Add(v,u); 68 n=max(n,u);n=max(n,v); 69 } 70 for(int i=1;i<=n;i++) 71 if(dfn[i]==0)Dfs(i,-1); 72 for(int i=1;i<=n;i++) 73 if(c[i]==0&&f[i]==0){ 74 sum++;dfs(i); 75 } 76 if(sum==1){ 77 ans=2;cnt=cnt*(ll)n*(n-1)/2; 78 } 79 else { 80 for(int i=1;i<=sum;i++) 81 if(r[i]==1){ 82 ans++;cnt=cnt*(ll)size[i]; 83 } 84 } 85 printf("Case %d: %d ",++cas,ans);cout<<cnt<<endl; 86 } 87 return 0; 88 }