最大流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;
}
posted @ 2021-07-14 11:32  chy_2003  阅读(40)  评论(0编辑  收藏  举报