【学习笔记】基础图论:网络流(最大流篇)

这应该算是复习?所以写的比较浅

简介

网络就是一张图 G=(V,E),除了有源点和汇点,容量以外和普通的图没有区别

  • 容量:每条边都有一个容量

  • 源点:出发点

  • 汇点:结束点

  • 流:一个合法解称作一个流,也就是一条可以从源点到汇点的一条合法路径。

  • 流量:每条边各自被经过的次数称作其流量,最终收集的总数为整个流的流量。

网络流会满足以下两个性质

  • 容量限制:每条边的流量不超过其容量(水管会爆的)。

  • 流量平衡:对于除源点和汇点以外的点来说,其流入量一定等于流出量。

网络流一般可以分为以下几个问题:最大流,最小割,费用流

最大流

我们希望去最大化整张网络上的流量 |f|,这个问题就是最大流

在求最大流时我们一般会使用以下方法

  • 在图上找到一条增广路(从源点到汇点的路径)

  • 去掉增广路上的残量最小值 v

  • 将答案加上 v

  • 将增广路上所有边的残量减去 v,反向边的残量加上 v

这个方法称为 Ford–Fulkerson 增广

Ford-Fulkerson 增广 是不会死循环的,因为每次增广都会导致流量增加,而流量存在一个最大值

没有指定走的方向的情况下随便乱走是肯定不够优的,因此我们有两种算法可以考虑

Edmonds–Karp 算法

在最自然的情况下一定是考虑使用 BFS 来解的,

  • 如果在 Gf 上我们可以从 s 出发 BFSt,则我们找到了新的增广路

  • 对于增广路 p,我们计算出 p 经过的边的剩余容量的最小值 Δ=min(u,v)pcf(u,v)

    我们给 p 上的每条边都加上 Δ 流量,并给它们的反向边都退掉 Δ 流量,令最大流增加了 Δ

  • 因为我们修改了流量,所以我们得到新的 Gf,我们在新的 Gf 上重复上述过程,直至增广路不存在,则流量不再增加。

上界复杂度 O(|V||E|2),虽然我们一般跑不到 EK 的上界,但是复杂度还是不够

因此考虑优化

Dinic 算法

考虑在增广前先对 GfBFS 分层,即根据结点 u 到源点 s 的距离 d(u) 把结点分成若干层。

令经过 u 的流量只能流向下一层的结点 v,即删除 u 向层数标号相等或更小的结点的出边,我们称 Gf 剩下的部分为层次图

如果我们在层次图 GL 上找到一个最大的增广流 fb,使得仅在 GL 上是不可能找出更大的增广流的,则我们称 fbGL 的阻塞流

我们可以用以下步骤来设计 Dinic 算法:

  • GfBFS 出层次图 GL

  • GLDFS 出阻塞流 fb

  • fb 并到原先的流 f 中,即 ff+fb

  • 重复以上过程直到不存在从 st 的路径

此时的 f 就是最大流,复杂度为 O(|V|2E)

点击查看代码
inline bool bfs() {
    queue<int> q;
    memset(dep, 0, sizeof(int) * (n + 1));

    dep[S] = 1;
    q.push(S);
    while (q.size()) {
        int u = q.front();
        q.pop();
        for (int i = fir[u]; ~i; i = e[i].nxt) {
            int v = e[i].v;
            if ((!dep[v]) && (e[i].cap > e[i].flow)) {
                dep[v] = dep[u] + 1;
                q.push(v);
            }
        }
    }
    return dep[T];
}
inline int dfs(int u, int flow){
    if ((u == T) || (!flow)) 
        return flow;

    int ret = 0;
    for (int& i = cur[u]; ~i; i = e[i].nxt) {
        int v = e[i].v, d;
        if ((dep[v] == dep[u] + 1) && (d = dfs(v, min(flow - ret, e[i].cap - e[i].flow)))) {
            ret += d;
            e[i].flow += d;
            e[i ^ 1].flow -= d;
            if (ret == flow) 
                return ret;
        }
    }
    return ret;
}

inline void dinic() {
    while(bfs()){
        memcpy(cur, fir, sizeof(int) * (n + 1));
        maxflow += dfs(S, INF);
    }
}
posted @   Vsinger_洛天依  阅读(107)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 上周热点回顾(3.3-3.9)
· AI 智能体引爆开源社区「GitHub 热点速览」
· 写一个简单的SQL生成工具

阅读目录(Content)

此页目录为空

点击右上角即可分享
微信分享提示