給一個無向圖,包含 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 }