1. 程式人生 > >[BZOJ 2730][HNOI 2012] 礦場搭建

[BZOJ 2730][HNOI 2012] 礦場搭建

+= 之間 event 註意 分別是 lld com dfs tps

2730: [HNOI2012]礦場搭建

Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 2113 Solved: 979
[Submit][Status][Discuss]

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

Sample Output

Case 1: 2 4
Case 2: 4 1

HINT

Case 1 的四組解分別是(2,4),(3,4),(4,5),(4,6); Case 2 的一組解為(4,5,6,7)。

題意

給定一個無向圖, 分配最少的救援通道使任意一個結點斷開後所有其余結點都與至少一個救援通道連通.

題解

斷開一個點還能保持連通...除了點雙聯通分量還有誰?

每個點雙連通分量裏都至少要有一個並且為了保證最少只能有一個. 由於每個雙聯通分量中任選一個安置救援通道即可, 所以最終的方案數為各雙聯通分量的大小之積.

$Tarjan$ 求割頂然後亂搞也可以過.

參考代碼

GitHub

技術分享
  1 #include <cstdio>
  2 #include <cstring>
  3 #include <queue>
  4 
  5 const int MAXN=505;
  6 typedef long long LL;
  7 
  8 struct Edge{
  9     int to;
 10     Edge* next;
 11 };
 12 Edge E[MAXN];
 13 Edge* head[MAXN];
 14 Edge* top=E;
 15 
 16 int n,m,len,rt,son,ans,cnt,tot,Node,Case=0,Time,dfn[MAXN],low[MAXN],vis[MAXN];
 17 LL f;
 18 
 19 bool exist[MAXN],Gd[MAXN];
 20 
 21 void DFS(int);
 22 void Tarjan(int);
 23 void Initialize();
 24 void Insert(int,int);
 25 int main()
 26 {
 27     while(scanf("%d",&m)==1){
 28         if(m==0)
 29             break;
 30         Initialize();
 31         for(int i=1;i<=m;i++){
 32             if(exist[i] && !dfn[i]){
 33                 rt=i;
 34                 son=0;
 35                 Tarjan(i);
 36                 if(son>1 && !Gd[i])
 37                     Gd[i]=true;
 38             }
 39         }
 40         for(int i=1;i<=m+1;i++){
 41             if(!exist[i])
 42                 continue;
 43             if(!Gd[i]){
 44                 cnt=0;
 45                 Node=1;
 46                 tot++;
 47                 DFS(i);
 48                 if(!cnt){
 49                     ans+=2;
 50                     f=f*Node*1ll*(Node-1)/2;
 51                 }
 52                 else if(cnt==1){
 53                     ans++;
 54                     f=Node*1ll*f;
 55                 }
 56             }
 57         }
 58         printf("Case %d: %d %lld\n",Case,ans,f);
 59     }
 60     return 0;
 61 }
 62 
 63 void Initialize(){
 64     int x,y;
 65     memset(head,0,sizeof head);
 66     memset(exist,0,sizeof exist);
 67     memset(dfn,0,sizeof dfn);
 68     memset(low,0,sizeof low);
 69     memset(Gd,0,sizeof Gd);
 70     n=0;
 71     len=0;
 72     Time=0;
 73     rt=-1;
 74     f=1ll;
 75     ans=0;
 76     Case++;
 77 
 78     for(int i=1;i<=m;i++){
 79         scanf("%d%d",&x,&y);
 80         if(!exist[x]){
 81             exist[x]=1;
 82             n++;
 83         }
 84         if(!exist[y]){
 85             exist[y]=1;
 86             n++;
 87         }
 88         Insert(x,y);
 89         Insert(y,x);
 90     }
 91 }
 92 
 93 void DFS(int x){
 94     exist[x]=false;
 95     for(Edge* i=head[x];i!=NULL;i=i->next){
 96         if(!exist[i->to])
 97             continue;
 98         if(Gd[i->to] && vis[i->to]!=tot){
 99             vis[i->to]=tot;
100             cnt++;
101         }
102         else if(!Gd[i->to]){
103             Node++;
104             DFS(i->to);
105         }
106     }
107 }
108 
109 void Tarjan(int x){
110     low[x]=dfn[x]=++Time;
111     for(Edge* i=head[x];i!=NULL;i=i->next){
112         if(!dfn[i->to]){
113             Tarjan(i->to);
114             if(x==rt)
115                 son++;
116             else{
117                 low[x]=std::min(low[x],low[i->to]);
118                 if(low[i->to]>=dfn[x] && !Gd[x])
119                     Gd[x]=true;    
120             }
121         }
122         else low[x]=std::min(low[x],dfn[i->to]);
123     }
124 }
125 
126 void Insert(int from,int to){
127     top->to=to;
128     top->next=head[from];
129     head[from]=top;
130     top++;
131 }
Backup

技術分享

[BZOJ 2730][HNOI 2012] 礦場搭建