bzoj2730: [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)。
题解:
这题简直就是暴力。。。
显然在某个不是割点的点坍塌并没有什么事,考虑在割点坍塌的情况
先把所以的割点求出来然后删掉,现在会剩下若干个连通块
如果只有一个连通块,显然这个图没有割点,答案为n*(n-1)/2
如果一个连通块可以连接不少于两个,它就不用设置救援出口,否则要设置一个
code:
1 #include<cstdio> 2 #include<iostream> 3 #include<cmath> 4 #include<cstring> 5 #include<algorithm> 6 #define maxn 505 7 using namespace std; 8 char ch; 9 bool ok; 10 void read(int &x){ 11 for (ok=0,ch=getchar();!isdigit(ch);ch=getchar()) if (ch=='-') ok=1; 12 for (x=0;isdigit(ch);x=x*10+ch-'0',ch=getchar()); 13 if (ok) x=-x; 14 } 15 int n,m,a[maxn],b[maxn],u,v; 16 int list[maxn<<1]; 17 int tot,now[maxn],son[maxn<<1],pre[maxn<<1]; 18 int idx,dfn[maxn],low[maxn],deg,cnt,color[maxn],siz[maxn],sum[maxn],total,vis[maxn]; 19 long long ans; 20 bool flag,bo[maxn]; 21 void put(int a,int b){pre[++tot]=now[a],now[a]=tot,son[tot]=b;} 22 void dfs(int u,int fa){ 23 dfn[u]=low[u]=++idx; 24 for (int p=now[u],v=son[p];p;p=pre[p],v=son[p]) 25 if (!dfn[v]){ 26 dfs(v,u); 27 low[u]=min(low[u],low[v]); 28 if (dfn[u]<=low[v]){if (u!=1) flag=1,bo[u]=1; else deg++;} 29 } 30 else if (v!=fa) low[u]=min(low[u],dfn[v]); 31 } 32 void dfs2(int u){ 33 vis[u]=cnt,siz[cnt]++; 34 for (int p=now[u],v=son[p];p;p=pre[p],v=son[p]) 35 if (!bo[v]){if (vis[v]!=cnt) dfs2(v);} 36 else if (vis[v]!=cnt) vis[v]=cnt,sum[cnt]++; 37 } 38 int main(){ 39 int tim=0; 40 for (read(m);m;read(m)){ 41 n=tot=0,tim++; 42 memset(now,0,sizeof(now)); 43 for (int i=1;i<=m;i++) read(a[i]),read(b[i]),list[++n]=a[i],list[++n]=b[i]; 44 sort(list+1,list+n+1),n=unique(list+1,list+n+1)-list-1; 45 for (int i=1;i<=m;i++){ 46 u=lower_bound(list+1,list+n+1,a[i])-list; 47 v=lower_bound(list+1,list+n+1,b[i])-list; 48 put(u,v),put(v,u); 49 } 50 memset(dfn,0,sizeof(dfn)); 51 memset(low,0,sizeof(low)); 52 idx=deg=0,flag=0; 53 memset(bo,0,sizeof(bo)); 54 dfs(1,0); 55 if (deg>1) flag=1,bo[1]=1; 56 if (!flag) printf("Case %d: %d %d\n",tim,2,n*(n-1)/2); 57 else{ 58 memset(vis,0,sizeof(vis)); 59 memset(siz,0,sizeof(siz)); 60 memset(sum,0,sizeof(sum)); 61 total=cnt=0,ans=1; 62 for (int i=1;i<=n;i++) if (!bo[i]&&!vis[i]){ 63 ++cnt,dfs2(i); 64 if (sum[cnt]==1) ans=ans*siz[cnt],total++; 65 } 66 printf("Case %d: %d %lld\n",tim,total,ans); 67 } 68 } 69 return 0; 70 }