1. 程式人生 > 其它 >最大流EK(Edmonds-Karp)

最大流EK(Edmonds-Karp)

最大流相關知識

演算法思路

每次在殘量網路上BFS找增廣路進行增廣。演算法較為簡明簡單,下面主要討論時間複雜度。

設有 \(n\) 個點 \(m\) 條邊,則每次增廣耗時 \(O(n+m)\) 。下證最多增廣 \(O(mn)\) 次。

由於使用 \(BFS\) 進行增廣,所以每次增廣都是從起點到終點的最短路。比較顯然的是,每次增廣之後所有點到起點的最短路不變小。

定義限制此次增廣最大流量的為關鍵邊,於是此次增廣後,這條邊(設從 \(u\)\(v\) )就會消失。這條邊再次出現的條件是這條邊的反向邊被增廣。於是這條邊再次成為關鍵邊的必要不充分條件是它的反向邊被增廣。

考察兩個點到起點的距離 \(d[u]\)

\(d[v]\) 。這條邊被刪時是 \(d[v]=d[u]+1\) ,它的反向邊被增廣時是 \(d[u]=d[v]+1\) 。由於 \(d\) 只變大不變小,所以至少是 \(d[v]\) 變大了 \(2\) 。所以這條邊成為關鍵邊的次數至多為 \(O(n)\)

每次增廣都有一條關鍵邊,所以最多增廣 \(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;
}