ZOJ 2753 Min Cut (Destroy Trade Net)(無向圖全局最小割)

 

題目大意

 

給一個無向圖,包含 N 個點和 M 條邊,問最少刪掉多少條邊使得圖分爲不連通的兩個部分,圖中有重邊html

數據範圍:2<=N<=500, 0<=M<=N*(N-1)/2ios

 

作法分析

 

典型的無向圖全局最小割,使用 Stoer-Wagner 算法算法

 

Stoer-Wagner 算法共執行 n-1 次 BFS,每次 BFS 獲得一個當前圖的最小 S-T 割,而且將最後 BFS 的兩個點縮點,n-1 次 BFS 獲得 n-1 個最小 S-T 割中的最小者就是整個無向圖的全局最小割,爲了講述每次 BFS 執行的操做,先進行以下定義:ide

  令 g[i][j] 表示邊 (i, j) 的權值,對於無向圖,咱們有 g[i][j]=g[j][i]優化

  令 w[u] 表示 u 和已經被 BFS 過的點的關聯度,即 w[u]=∑g[v][u] 其中,v 是已經被 BFS 過的點,u 是未被 BFS 的點。初始時,全部點的 w 值所有爲 0spa

  令 vs[u] 表示 u 是否已經被 BFS 過,vs[u]=1 表示 u 已經被 BFS 過。初始時,全部點的 vs 值所有爲 0code

 

每次 BFS 按以下步驟執行:htm

  1. 選出未被 BFS 過的點中,關聯度(w 值)最大的點(若是有多個,任選一個),設爲 u。若是全部的點都已經被 BFS 過,則退出當前 BFS 過程blog

  2. 用 u 更新全部未被 BFS 的點的關聯度,即: w[v]+=g[u][v],其中 v 沒有被 BFS 過get

  3. 將 u 設置爲 BFS 過,即將 vs[u] 的值由 0 變爲 1

  設倒數第 2 個被 BFS 的點爲 S,倒數第 1 個被 BFS 的點爲 T,那麼,w[T] 就是本次 BFS 獲得的最小 S-T 割

每次 BFS 後,將最後 BFS 的兩個點 S 和 T 縮成一個點 u,即:g[i][u]=g[i][S]+g[i][T]

每次 BFS 後,用獲得的最小 S-T 割更新全局的最小割

 

n-1 次 BFS 後,全局最小割求出來了,圖也被縮成了一個點

 

下面是一個例子

假設在進行 BFS 時有一個無向圖以下:

圖中,括號中的數字表示每一個點的 w 值,初始化爲 0,邊上的值表示邊權。如今選擇一個具備最大關聯度(w 值最大)的點,有多種選擇時隨意選取一個點,假設選取的是第 2 個點,將它標記爲已經訪問過的點,並更新其餘未被訪問過的點的關聯度:

如今,第 3 個點的關聯度最大,選它做爲下一個 BFS 的點,將它標記爲已經訪問過的點,並用它更新其餘未被訪問過的點的關聯度:

第 4 個點的關聯度最大,選其做爲下一個 BFS 的點,將它標記爲已經訪問過的點,並更新其餘未被訪問過的點的關聯度:

第 7 個點的關聯度最大,選其做爲下一個 BFS 的點,將它標記爲已經訪問過的點,並更新其餘未被訪問過的點的關聯度:

第 8 個點的關聯度最大,選其做爲下一個 BFS 的點,將它標記爲已經訪問過的點,並更新其餘未被訪問過的點的關聯度:

第 6 個點的關聯度最大,選其做爲下一個 BFS 的點,將它標記爲已經訪問過的點,並更新其餘未被訪問過的點的關聯度:

第 5 個點的關聯度最大,選其做爲下一個 BFS 的點,將它標記爲已經訪問過的點,並更新其餘未被訪問過的點的關聯度:

第 1 個點的關聯度最大,選其做爲下一個 BFS 的點,將它標記爲已經訪問過的點,並更新其餘未被訪問過的點的關聯度:

至此,全部的點都被 BFS 了一遍,最後訪問的點是 1,倒數第二訪問的點是 5:

那麼,咱們此次 BFS 的 S 點是 5,T 點是 1,此次 BFS 獲得的最小 S-T 割爲 w[T]=5(上圖中綠色的點)

將 S 點和 T 點合併:

獲得新圖:

將全部的標記(包括關聯度,是否訪問過)清空,進行下一次 BFS ,直至全部的點縮成一個點爲止:

這樣,通過 n-1 次 BFS 以後,整個無向圖的全局最小割就求出來了

時間複雜度不難分析:o(n^3)

 

可是,我想,若是在每次 BFS 的時候,就像 Dijkstra 同樣用堆優化,應該能夠把複雜度下降到 o(n^2log2(n))

 

詳細證實,請看 A Simple Min-Cut Algorithm

 

參考代碼

 

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 
 5 using namespace std;
 6 
 7 struct Stoer_Wagner {
 8     static const int N=506, INF=(1<<30);
 9     int G[N][N], W[N], Merge[N], S, T, minCut, n;
10     bool vs[N];
11 
12     void init(int _n) {
13         n=_n;
14         memset(G, 0, sizeof G);
15     }
16 
17     void BFS() {
18         memset(vs, 0, sizeof vs);
19         memset(W, 0, sizeof W);
20         S=T=-1;
21         int Max, id;
22         for(int cnt=0; cnt<n; cnt++) {
23             Max=-INF;
24             for(int i=0; i<n; i++)
25                 if(!Merge[i] && !vs[i] && W[i]>Max)
26                     Max=W[i], id=i;
27             if(id==T) return;
28             S=T, T=id;
29             minCut=Max;
30             vs[id]=1;
31             for(int i=0; i<n; i++) {
32                 if(Merge[i] || vs[i]) continue;
33                 W[i]+=G[id][i];
34             }
35         }
36     }
37 
38     int StoerWagner() {
39         memset(Merge, 0, sizeof Merge);
40         int ans=INF;
41         for(int cnt=1; cnt<n; cnt++) {
42             BFS();
43             if(minCut<ans) ans=minCut;
44             if(ans==0) return ans;
45             Merge[T]=1;
46             for(int i=0; i<n; i++) {
47                 if(Merge[i]) continue;
48                 G[S][i]+=G[T][i];
49                 G[i][S]+=G[i][T];
50             }
51         }
52         return ans;
53     }
54 };
55 
56 Stoer_Wagner fuck;
57 int n, m;
58 
59 int main() {
60     while(scanf("%d%d", &n, &m)!=EOF) {
61         fuck.init(n);
62         for(int i=0, a, b, c; i<m; i++) {
63             scanf("%d%d%d", &a, &b, &c);
64             fuck.G[a][b]+=c;
65             fuck.G[b][a]+=c;
66         }
67         printf("%d\n", fuck.StoerWagner());
68     }
69     return 0;
70 }
ZOJ 2753

 

題目連接 & AC 通道

 

ZOJ 2753 Min Cut (Destroy Trade Net)

相關文章
相關標籤/搜索