最大流EK(Edmonds-Karp)
阿新 • • 發佈:2021-07-14
演算法思路
每次在殘量網路上BFS找增廣路進行增廣。演算法較為簡明簡單,下面主要討論時間複雜度。
設有 \(n\) 個點 \(m\) 條邊,則每次增廣耗時 \(O(n+m)\) 。下證最多增廣 \(O(mn)\) 次。
由於使用 \(BFS\) 進行增廣,所以每次增廣都是從起點到終點的最短路。比較顯然的是,每次增廣之後所有點到起點的最短路不變小。
定義限制此次增廣最大流量的為關鍵邊,於是此次增廣後,這條邊(設從 \(u\) 到 \(v\) )就會消失。這條邊再次出現的條件是這條邊的反向邊被增廣。於是這條邊再次成為關鍵邊的必要不充分條件是它的反向邊被增廣。
考察兩個點到起點的距離 \(d[u]\)
每次增廣都有一條關鍵邊,所以最多增廣 \(O(nm)\) 次。
總時間複雜度為 \(O(nm(n+m))\) ,實際操作時遠小於這個值。
題目
參考程式
#include <bits/stdc++.h> const int Maxn = 110; const int Maxm = 5010; int n, m, s, t; int u, v, c; namespace graph { struct edge { int To, Remain, Next; edge() {} edge(int _To, int _Remain, int _Next) : To(_To), Remain(_Remain), Next(_Next) {} }; int Start[Maxn], Space; edge Edge[Maxm << 1]; inline void Init() { Space = 0; memset(Start, 255, sizeof(Start)); return; } inline void AddEdge(int u, int v, int c) { Edge[Space++] = edge(v, c, Start[u]); Start[u] = Space - 1; Edge[Space++] = edge(u, 0, Start[v]); Start[v] = Space - 1; return; } } long long Edmonds_Karp_EK(int Start, int Destination); int main() { scanf("%d%d%d%d", &n, &m, &s, &t); graph::Init(); for (int i = 1; i <= m; ++i) { scanf("%d%d%d", &u, &v, &c); graph::AddEdge(u, v, c); } printf("%lld\n", Edmonds_Karp_EK(s, t)); return 0; } int Vis[Maxn], From[Maxn], Index[Maxn]; int Head, Tail, Queue[Maxn], Temp; int BFS(int Start, int Destination) { int Ans = 0; memset(Vis, 0, sizeof(Vis)); Head = Tail = 1; Queue[Tail] = Start; Vis[Start] = INT_MAX; while (Head <= Tail) { //printf("%d %d\n", Queue[Head], Vis[Queue[Head]]); for (int t = graph::Start[Queue[Head]]; t != -1; t = graph::Edge[t].Next) { //printf(" %d\n", graph::Edge[t].To); if (graph::Edge[t].Remain <= 0) continue; if (Vis[graph::Edge[t].To] != 0) continue; Vis[graph::Edge[t].To] = std::min(Vis[Queue[Head]], graph::Edge[t].Remain); From[graph::Edge[t].To] = Queue[Head]; Index[graph::Edge[t].To] = t; Queue[++Tail] = graph::Edge[t].To; } ++Head; } Ans = Vis[Destination]; if (Ans) { //printf("\n\n\nFind %d\n", Ans); Temp = Destination; while (Temp != Start) { //printf(" %d\n", Temp); graph::Edge[Index[Temp]].Remain -= Ans; graph::Edge[Index[Temp] ^ 1].Remain += Ans; Temp = From[Temp]; } //printf(" %d\n", Temp); } return Ans; } long long Edmonds_Karp_EK(int Start, int Destination) { long long Ans = 0, Temp = 0; Temp = BFS(Start, Destination); while (Temp) Ans += Temp, Temp = BFS(Start, Destination); return Ans; }