codevs 1996 矿场搭建
1996 矿场搭建
时间限制: 1 s
空间限制: 256000 KB
题目等级 : 大师 Master
题目描述 Description
煤矿工地可以看成是由隧道连接挖煤点组成的无向图。为安全起见,希望在工地发生事故时所有挖煤点的工人都能有一条出路逃到救援出口处。于是矿主决定在某些挖煤点设立救援出口,使得无论哪一个挖煤点坍塌之后,其他挖煤点的工人都有一条道路通向救援出口。
请写一个程序,用来计算至少需要设置几个救援出口,以及不同最少救援出口的设置方案总数。
输入描述 Input Description
输入文件有若干组数据,每组数据的第一行是一个正整数N(N≤500),表示工地的隧道数,接下来的N 行每行是用空格隔开的两个整数S 和T,表示挖煤点S 与挖煤点T 由隧道直接连接。输入数据以0 结尾。
输出描述 Output Description
输入文件中有多少组数据,输出文件中就有多少行。每行对应一组输入数据的结果。其中第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
数据范围及提示 Data Size & Hint
Case 1 的四组解分别是(2,4),(3,4),(4,5),(4,6);
Case 2 的一组解为(4,5,6,7)。
/* 额 刚开始求得缩点后度为1的结果不对 比如 缩完点后只有一个点等 正解 先求出割点 割点将其他的分成很多部分 这些部分 连着2个以上割点的不用建 连着1个割点的要建一个 连着0个割点的要建两个 */ #include<iostream> #include<cstdio> #include<cstring> #define LL long long #define maxn 510 using namespace std; LL n,m,topt,tot,anst,answ,sum; LL first[maxn]; LL dfn[maxn],low[maxn]; LL c[maxn],f[maxn],p[maxn],num[maxn]; struct edge { LL to; LL next; }e[maxn*2]; LL init() { LL x=0,f=1;char c=getchar(); while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} return x*f; } void Clean() { n=0;topt=0;anst=0,answ=1;sum=0; memset(first,0,sizeof(first)); memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low)); memset(num,0,sizeof(num)); memset(c,0,sizeof(c)); memset(p,0,sizeof(p)); memset(f,0,sizeof(f)); } void add(LL x,LL y) { topt++; e[topt].to=y; e[topt].next=first[x]; first[x]=topt; } LL get(LL x) { if(x&1)return x+1; else return x-1; } void tarjan(LL now,LL from) { LL s=0; dfn[now]=low[now]=++tot; for(LL i=first[now];i;i=e[i].next) { if(get(i)==from)continue; LL to=e[i].to; if(!dfn[to]) { tarjan(to,i);s++; low[now]=min(low[now],low[to]); if(low[to]>=dfn[now])c[now]++; } else low[now]=min(low[now],dfn[to]); } if(from==0)c[now]=s-1; } LL C(LL m,LL n) { LL ret=1; for(LL i=1;i<=n;i++) ret=ret*(m-i+1)/i; return ret; } int dfs(int x) { if(c[x]>0) { if(p[x]==1)return 0; p[x]=1;return 1; } int ret=0; f[x]=sum;num[sum]++; for(int i=first[x];i;i=e[i].next) { int to=e[i].to; if(!f[to])ret+=dfs(to); } return ret; } int main() { freopen("bzoj_2730.in","r",stdin); freopen("bzoj_2730.out","w",stdout); LL T=0; while(1) { m=init(); if(m==0)break; Clean(); for(LL i=1;i<=m;i++) { LL x,y; x=init();y=init(); n=max(n,max(x,y)); add(x,y);add(y,x); } for(LL i=1;i<=n;i++) if(!dfn[i])tarjan(i,0); for(int i=1;i<=n;i++) { if(c[i]>0)continue; if(f[i]==0) { memset(p,0,sizeof(p)); sum++; int ha=dfs(i); if(ha>=2)continue; if(ha==1)anst++,answ=answ*num[sum]; if(ha==0) { anst++;if(num[sum]==1)continue; anst++,answ=answ*C(num[sum],2); } } } cout<<"Case "<<++T<<": "<<anst<<" "<<answ<<endl; } return 0; }