1. 程式人生 > >BZOJ2730: [HNOI2012]礦場搭建

BZOJ2730: [HNOI2012]礦場搭建

pla 如果 str cnblogs () src png gif 搭建

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 }
View Code

BZOJ2730: [HNOI2012]礦場搭建