[HNOI2012]矿场搭建
【题目描述】
【输入格式】
输入文件有若干组数据,每组数据的第一行是一个正整数 N(N≤500),表示工地的隧道数,接下来的 N 行每行是用空格隔开的两个整数 S 和 T,表示挖煤点 S 与挖煤点 T 由隧道直接连接。输入数据以 0 结尾。
【输出格式】
输入文件中有多少组数据,输出文件 output.txt 中就有多少行。每行对应一组输入数据的 结果。其中第 i 行以 Case i: 开始(注意大小写,Case 与 i 之间有空格,i 与:之间无空格,: 之后有空格),其后是用空格隔开的两个正整数,第一个正整数表示对于第 i 组输入数据至少需 要设置几个救援出口,第二个正整数表示对于第 i 组输入数据不同最少救援出口的设置方案总 数。输入数据保证答案小于 2^64。输出格式参照以下输入输出样例。
【样例输入】
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
【样例输出】
Case 1: 2 4
Case 2: 4 1
【提示】
Case 1 的四组解分别是(2,4),(3,4),(4,5),(4,6);
Case 2 的一组解为(4,5,6,7)。
比较明显的tarjan求割点
一开始我想错了 以为挖煤点随便塌,数量不限。。
回到正题,既然是要在任意一个挖煤点塌了之后可以跑到救援点
那这救援点一定不能放在割点上 要不你就哭去吧
那就显然求出所有割点 再求其他连通块
显然有这样的结论:
1丶全图无割点 只有一个连通块 那就随意放两个救援点
因为万一塌了一个救援点 你还有另一个嘛 方案数C(n,2);
2丶一个连通块连着一个割点,在连通块中放一个救援点
此连通块中的任意一个点都可以放,根据乘法原理方案数=原方案数*连通块的点数
3丶一个连通块连着两个或以上的割点 那就不用安放救援点
因为路有多条 塌了一个割点 还有其他路可走
1 #include <cctype> 2 #include <cstdio> 3 #include <cstring> 4 5 typedef long long LL; 6 7 const int MAXN=20010; 8 9 int m,n,id,top,inr,opt,cnt; 10 11 int dfn[MAXN],low[MAXN],stack[MAXN],cut[MAXN],belong[MAXN],siz[MAXN],c[MAXN]; 12 13 bool vis[MAXN]; 14 15 LL ans; 16 17 struct node { 18 int to; 19 int next; 20 node(){} 21 node(int to,int next):to(to),next(next){} 22 }; 23 node e[MAXN]; 24 25 int head[MAXN],tot; 26 27 inline void read(int&x) { 28 int f=1;register char c=getchar(); 29 for(x=0;!isdigit(c);c=='-'&&(f=-1),c=getchar()); 30 for(;isdigit(c);x=x*10+c-48,c=getchar()); 31 x=x*f; 32 } 33 34 inline void clear() { 35 tot=0;top=0;inr=0;id=0;cnt=0;ans=1;n=0; 36 memset(c,0,sizeof c); 37 memset(dfn,0,sizeof dfn); 38 memset(vis,0,sizeof vis); 39 memset(low,0,sizeof low); 40 memset(cut,0,sizeof cut); 41 memset(siz,0,sizeof siz); 42 memset(head,-1,sizeof head); 43 memset(belong,0,sizeof belong); 44 } 45 46 struct RUNNING { 47 int min(int a,int b) {return a<b?a:b;} 48 49 void add(int x,int y) { 50 e[++tot]=node(y,head[x]); 51 head[x]=tot; 52 e[++tot]=node(x,head[y]); 53 head[y]=tot; 54 } 55 56 void tarjan(int u,int fa) { 57 dfn[u]=low[u]=++inr; 58 stack[++top]=u; 59 vis[u]=true; 60 int x=0; 61 for(int i=head[u];i!=-1;i=e[i].next) { 62 int v=e[i].to; 63 if(v==fa) continue; 64 if(!dfn[v]) { 65 ++x; 66 tarjan(v,u); 67 low[u]=min(low[u],low[v]); 68 if(dfn[u]<=low[v]) cut[u]=1; 69 } 70 else if(vis[v]) low[u]=min(low[u],dfn[v]); 71 } 72 if(fa==-1&&x<=1) cut[u]=0; 73 } 74 75 void Dfs(int u) { 76 vis[u]=true;++siz[id]; 77 for(int i=head[u];i!=-1;i=e[i].next) { 78 int v=e[i].to; 79 if(vis[v]) continue; 80 if(!cut[v]) Dfs(v); 81 else if(belong[v]!=id) { 82 belong[v]=id; 83 ++c[id]; 84 } 85 } 86 } 87 88 } yf; 89 90 int hh() { 91 freopen("bzoj_2730.in","r",stdin); 92 freopen("bzoj_2730.out","w",stdout); 93 while(true) { 94 read(m); 95 if(!m) break; 96 clear(); 97 for(int x,y;m--;) { 98 read(x);read(y); 99 yf.add(x,y); 100 if(x>n) n=x; 101 if(y>n) n=y; 102 } 103 for(int i=1;i<=n;++i) 104 if(!dfn[i]) yf.tarjan(i,-1); 105 memset(vis,false,sizeof vis); 106 for(int i=1;i<=n;++i) 107 if(!cut[i]&&!vis[i]) ++id,yf.Dfs(i); 108 if(id==1) cnt=2,ans=(LL)n*(n-1)/2; 109 else { 110 for(int i=1;i<=id;++i) 111 if(c[i]==1) ++cnt,ans=(LL)ans*siz[i]; 112 } 113 printf("Case %d: %d %lld ",++opt,cnt,ans); 114 } 115 return 0; 116 } 117 118 int sb=hh(); 119 int main(int argc,char**argv) {;}