网络流-最大流

最大流问题:
源点source(S点)开始源源不断的通过中间的一些管道流到槽点sink(T点),求最后T点最大有多少流量。

常用的算法是增广路算法,通过不同的找增广路的方法会有不一样的复杂度,也分别为不同叫法,一般用DFS找增广路的算法叫 FF(Ford-Fulkerson)算法,用BFS的叫EK(Edmonds-Karp)算法。这里我主要记录一下EK算法。

一些概念
增广路: 这里网络流的增广路网络上的意思是指这条路径上的流可以修改,通过修改,使得整个网络的流值增大。。我的理解是可以从源点走到终点的一条路。
瓶颈: 增广路里面最小容量的边。

最大流的增广路算法步骤:
首先建立有向图,给每条有向边再建立一条反边。设mf(maximum flow)为最大流。

  1. 找增广路(一条从源点到终点的可行路),找到瓶颈容量 f。
  2. 增广路上每条正边减去瓶颈容量 f,每条负边加上 f。
  3. mf 加上瓶颈容量f。
    重复1.2过程,直到没有增广路。
    mf 就是等于每条增广路的瓶颈容量之和。

影响算法复杂度的主要因素是找增广路的步骤。其他改进找增广路的方法的算法有Dinic算法,Capacity-Scaling算法。

例子:图中的最大流为20
网络流-最大流_第1张图片
python代码:
邻接矩阵版本

# EK算法

# 广搜寻找增广路
def bfs(start, end, graph):
    q = [[start, 9999999, [start]]]
    vis = [False] * len(graph)
    vis[start] = True
    while q:
        nd, f, path = q.pop(0)
        if nd == end:
            return f, path
        for v, c in enumerate(graph[nd]):
            pa = path[:]
            if c > 0 and not vis[v]:
                pa.append(v)
                q.append([v, min(f, c), pa])
                vis[v] = True
    return False


def max_flow(start, end, graph):
    mf = 0
    while True:
        # 找增广路以及瓶颈流
        result = bfs(start, end, graph)
        # 当找不到增广路时算法停止,得到最大流
        if result:
            f, aug_path = result
            # 更新增广路的正负边的权值
            for i in range(len(aug_path) - 1):
                u, v = aug_path[i], aug_path[i + 1]
                graph[u][v] -= f
                graph[v][u] += f
            # 最大流总数加上瓶颈流
            mf += f
        else:
            return mf


edges = [
    [4, 0, 10],
    [4, 1, 10],
    [0, 2, 25],
    [1, 3, 15],
    [3, 0, 6],
    [2, 5, 10],
    [3, 5, 10]
]

n = 6

# 源点与汇点
from_node, to_node = 4, 5

# directed graph
# 邻接矩阵
graph = [[0] * n for _ in range(n)]

# 构图:邻接表
for u, v, c in edges:
    # 有重边的加等,不能重边的直接赋值
    graph[u][v] += c
    # graph[u][v] = c

print(max_flow(from_node, to_node, graph))

你可能感兴趣的:(算法与数据结构)