• 最大流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
    ", 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
    ", Queue[Head], Vis[Queue[Head]]);
            for (int t = graph::Start[Queue[Head]]; t != -1; t = graph::Edge[t].Next) {
                //printf("    %d
    ", 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("
    
    
    Find %d
    ", Ans);
            Temp = Destination;
            while (Temp != Start) {
                //printf("   %d
    ", Temp);
                graph::Edge[Index[Temp]].Remain -= Ans;
                graph::Edge[Index[Temp] ^ 1].Remain += Ans;
                Temp = From[Temp];
            }
            //printf("   %d
    ", 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;
    }
    
  • 相关阅读:
    Wolfram常用计算
    soapUI接口关联教程
    时间序列预测线上充值数据
    基于MySQL分析线上充值留存率
    更改用户资料需要完善脚本
    MySQL建立RFM模型
    Scrcpy使用入门
    虾皮Shopee社招面经分享(大数据开发方向),附内推方式
    MySQL Binlog 解析工具 Maxwell 详解
    MySQL Binlog 介绍
  • 原文地址:https://www.cnblogs.com/chy-2003/p/15010086.html
Copyright © 2020-2023  润新知