MaxFlow/gpt/code.md
2024-12-17 16:53:26 +08:00

4.3 KiB
Raw Blame History

好的,以下是使用 Dinic's Algorithm 实现最大流问题的 Python 代码。Dinic 算法比 Edmonds-Karp 更高效,尤其是在稀疏图中。它使用分层网络和每一层的增广路径来提高效率。

Dinic算法的Python实现

from collections import deque

class MaxFlow:
    def __init__(self, vertices):
        self.V = vertices  # 图的顶点数
        self.graph = [[] for _ in range(vertices)]  # 邻接表表示图
        self.level = [-1] * vertices  # 层次标记
        self.ptr = [0] * vertices  # 每个节点在其邻接边中的指针

    def add_edge(self, u, v, capacity):
        """添加从u到v的边并反向边的容量初始化为0"""
        self.graph[u].append([v, capacity, len(self.graph[v])])  # (目标点, 容量, 反向边的索引)
        self.graph[v].append([u, 0, len(self.graph[u]) - 1])  # (源点, 容量0, 反向边的索引)

    def bfs(self, source, sink):
        """BFS进行分层图构建"""
        queue = deque([source])
        self.level = [-1] * self.V
        self.level[source] = 0

        while queue:
            u = queue.popleft()

            for v, cap, _ in self.graph[u]:
                if self.level[v] == -1 and cap > 0:  # 未访问且容量大于0
                    self.level[v] = self.level[u] + 1
                    if v == sink:
                        return True
                    queue.append(v)

        return False

    def dfs(self, u, sink, flow):
        """DFS寻找增广路径并更新残余图"""
        if u == sink:
            return flow
        while self.ptr[u] < len(self.graph[u]):
            v, cap, rev = self.graph[u][self.ptr[u]]
            if self.level[v] == self.level[u] + 1 and cap > 0:
                current_flow = min(flow, cap)
                result = self.dfs(v, sink, current_flow)
                if result > 0:
                    # 更新正向边和反向边
                    self.graph[u][self.ptr[u]][1] -= result
                    self.graph[v][rev][1] += result
                    return result
            self.ptr[u] += 1
        return 0

    def dinic(self, source, sink):
        """Dinic算法计算最大流"""
        max_flow = 0
        while self.bfs(source, sink):
            self.ptr = [0] * self.V
            while True:
                flow = self.dfs(source, sink, float('Inf'))
                if flow == 0:
                    break
                max_flow += flow
        return max_flow


# 示例
if __name__ == "__main__":
    vertices = 6
    g = MaxFlow(vertices)
    
    # 添加边及其容量
    g.add_edge(0, 1, 16)
    g.add_edge(0, 2, 13)
    g.add_edge(1, 2, 10)
    g.add_edge(1, 3, 12)
    g.add_edge(2, 1, 4)
    g.add_edge(2, 4, 14)
    g.add_edge(3, 2, 9)
    g.add_edge(3, 5, 20)
    g.add_edge(4, 3, 7)
    g.add_edge(4, 5, 4)
    
    source = 0  # 源点
    sink = 5    # 汇点

    max_flow = g.dinic(source, sink)
    print("最大流为:", max_flow)

代码解释:

  1. 添加边: add_edge(u, v, capacity) 方法将一条从节点 uv 的边加入图中,且边的容量为 capacity。同时,在反向边上初始化容量为 0。
  2. BFS层次图构建 bfs(source, sink) 方法通过广度优先搜索构建分层网络,标记每个节点的层次,帮助找增广路径。
  3. DFS增广路径 dfs(u, sink, flow) 方法通过深度优先搜索,在层次网络中寻找增广路径并进行流量传递。
  4. Dinic算法 dinic(source, sink) 方法利用层次图和增广路径相结合的方式进行多轮流量增广,直到没有更多增广路径为止。

算法分析:

  1. 时间复杂度:

    • 每轮BFS的时间复杂度为 (O(V + E))
    • 每轮DFS的时间复杂度为 (O(E))。
    • 总体时间复杂度为 (O(V^2 E))在稀疏图中相较于Edmonds-Karp更为高效。
  2. 空间复杂度:

    • 使用了邻接表来表示图,空间复杂度为 (O(V + E))其中V为节点数E为边数。

实验输出:

运行代码后,输出的最大流值如下:

最大流为: 23

总结:

使用 Dinic 算法可以在稀疏图中高效计算最大流,比 Edmonds-Karp 更加高效尤其在实际问题中当图的边数和顶点数较大时Dinic 算法的表现尤为突出。

如果有任何问题或者需要进一步的解释,随时告诉我!