BZOJ2730: [HNOI2012]矿场搭建
n<=500条边的图,求:最少设置多少关键点,使得当任意某一个点不能经过时其他点都至少能到达一个关键点,并输出方案数。
tarjan求点双,如果一个点双里面没有割点,那这就是一个孤立的点双分量,至少要设置两个点。如果有割点,大概是这样的情况:
红色的这些“叶子”分量,也就是只有一个割点的分量,是一定要设置一个关键点的,因为如果唯一的割点走不了了,这个分量的点就只能在分量里面活动了,而这样也可以使其他有多个割点的分量可以在一个割点被破坏时到达其他的关键点。方案数就乘上这些分量的大小-1即可。
在一个块里选两个点的方案记得除以2。。。。。
1 #include<stdio.h> 2 #include<string.h> 3 #include<stdlib.h> 4 #include<algorithm> 5 //#include<assert.h> 6 #include<math.h> 7 //#include<iostream> 8 using namespace std; 9 10 int n,m; 11 #define maxn 1011 12 #define maxm 2011 13 int id[maxn],cntid; 14 struct Edge{int to,next;}edge[maxm];int first[maxn],le; 15 int getid(int x) {if (id[x]) return id[x];return (id[x]=++cntid);} 16 void in(int x,int y) {Edge &e=edge[le];e.to=y;e.next=first[x];first[x]=le++;} 17 void insert(int x,int y) {in(x,y);in(y,x);} 18 int low[maxn],dfn[maxn],Time,tot,bel[maxn],size[maxn],cut[maxn],sta[maxm],top;bool iscut[maxn]; 19 void tarjan(int x,int fa) 20 { 21 low[x]=dfn[x]=++Time; 22 int son=0; 23 for (int i=first[x];i;i=edge[i].next) 24 { 25 Edge &e=edge[i]; 26 if (!dfn[e.to]) 27 { 28 sta[++top]=i; 29 son++; 30 tarjan(e.to,x); 31 low[x]=min(low[x],low[e.to]); 32 if (low[e.to]>=dfn[x]) 33 { 34 iscut[x]=1;tot++;size[tot]=cut[tot]=0; 35 for (;;) 36 { 37 int u=edge[sta[top]].to,v=edge[sta[top]^1].to; 38 if (bel[u]!=tot) bel[u]=tot,size[tot]++,cut[tot]+=iscut[u]; 39 if (bel[v]!=tot) bel[v]=tot,size[tot]++,cut[tot]+=iscut[v]; 40 top--; 41 if (v==x && u==e.to) break; 42 } 43 } 44 } 45 else if (e.to!=fa && dfn[e.to]<dfn[x]) 46 { 47 sta[++top]=i; 48 low[x]=min(low[x],dfn[e.to]); 49 } 50 } 51 if (!fa && son<=1) iscut[x]=0,cut[bel[x]]--; 52 } 53 void tarjan() 54 { 55 memset(dfn,0,sizeof(dfn)); 56 memset(bel,0,sizeof(bel)); 57 memset(iscut,0,sizeof(iscut)); 58 Time=tot=top=0; 59 for (int i=1;i<=n;i++) 60 if (!dfn[i]) tarjan(i,0); 61 } 62 #define LL long long 63 int main() 64 { 65 int x,y,Case=0; 66 while (scanf("%d",&n) && n) 67 { 68 cntid=0;le=2; 69 memset(first,0,sizeof(first)); 70 memset(id,0,sizeof(id)); 71 for (int i=1;i<=n;i++) 72 { 73 scanf("%d%d",&x,&y); 74 x=getid(x),y=getid(y); 75 insert(x,y); 76 } 77 m=n;n=cntid; 78 tarjan(); 79 LL ans=1,sum=0; 80 for (int i=1;i<=tot;i++) 81 { 82 if (!cut[i]) sum+=2,ans=ans*size[i]*(size[i]-1)/2; 83 else if (cut[i]==1) sum++,ans=ans*(size[i]-1); 84 } 85 printf("Case %d: %lld %lld\n",++Case,sum,ans); 86 } 87 return 0; 88 }