网络流学习笔记(基础)

王树森教程

基础概念

流网络(Flow Network):有向图 G = ( V , E ) G = (V, E) G=(V,E),每条边 ( u , v ) ∈ E (u, v) \in E (u,v)∈E有容量 c ( u , v ) ≥ 0 c(u, v) \geq 0 c(u,v)≥0,约定:若 ( u , v ) ∉ E (u, v) \notin E (u,v)∈/E,则 c ( u , v ) = 0 c(u, v) = 0 c(u,v)=0

可行流(Feasible Flow):满足以下条件的流函数 f : V × V → R f: V \times V \rightarrow \mathbb{R} f:V×V→R:,容量限制: 0 ≤ f ( u , v ) ≤ c ( u , v ) 0 \leq f(u, v) \leq c(u, v) 0≤f(u,v)≤c(u,v),流量守恒:对任意 u ≠ s , t u \neq s, t u=s,t,有
∑ v ∈ V f ( v , u ) = ∑ v ∈ V f ( u , v ) \sum_{v \in V} f(v, u) = \sum_{v \in V} f(u, v) ∑v∈Vf(v,u)=∑v∈Vf(u,v)

最大流问题:寻找从源点 s s s到汇点 t 的可行流,使得流量 的可行流,使得流量 的可行流,使得流量\|f\| = \\sum_{v \\in V} f(s, v)最大化

层次图(Level Graph):从源点 s s s出发进行 BFS,记录每个节点的层次 l e v e l [ u ] level[u] level[u](即 s s s到 u u u的最短距离)

阻塞流(Blocking Flow):在层次图中无法再找到从 s s s 到 t 的路径时的流,不一定是最大流,但能保证每一步有效推进


核心算法

1. Ford-Fulkerson 方法

核心思想:通过残留网络寻找增广路径

步骤:

  1. 初始化残留网络 G f G_f Gf(初始时 G f = G G_f = G Gf=G)
  2. 在 G f G_f Gf中寻找一条 s → t s \rightarrow t s→t的路径(增广路径)
  3. 计算路径上的最小残留容量 Δ = min ⁡ { c f ( u , v ) } \Delta = \min\{c_f(u, v)\} Δ=min{cf(u,v)}
  4. 沿路径增加流量 Δ \Delta Δ,更新残留网络
  5. 重复直到没有增广路径
2. Edmonds-Karp 算法

改进点:使用 BFS 寻找最短增广路径

python 复制代码
def edmonds_karp(graph, s, t):
    # 初始化残留网络和流量
    max_flow = 0
    while True:
        # BFS 寻找增广路径
        parent = bfs(residual_graph, s, t)
        if not parent[t]: break
        # 计算最小残留容量
        delta = INF
        v = t
        while v != s:
            u = parent[v]
            delta = min(delta, residual_graph[u][v])
            v = u
        # 更新残留网络
        v = t
        while v != s:
            u = parent[v]
            residual_graph[u][v] -= delta
            residual_graph[v][u] += delta
            v = u
        max_flow += delta
    return max_flow
3. Dinic 算法

优化策略:

  1. 分层图(Level Graph):BFS 构建层次结构
  2. 阻塞流(Blocking Flow):DFS 多路增广

三阶段循环:

  1. BFS 构建层次图(Level Graph)
  2. DFS 寻找阻塞流(Blocking Flow)
  3. 更新残留网络并累加流量

数据结构设计

python 复制代码
class Edge:
    def __init__(self, to, rev, capacity):
        self.to = to    # 指向的节点
        self.rev = rev  # 反向边在邻接表中的索引
        self.cap = capacity  # 剩余容量

class Dinic:
    def __init__(self, n):
        self.size = n
        self.graph = [[] for _ in range(n)]  # 邻接表存储
    
    def add_edge(self, fr, to, cap):
        # 正向边
        forward = Edge(to, len(self.graph[to]), cap)
        # 反向边(初始容量0)
        backward = Edge(fr, len(self.graph[fr]), 0)
        self.graph[fr].append(forward)
        self.graph[to].append(backward)

分层图构建(BFS)

python 复制代码
def bfs_level(self, s, t):
    level = [-1] * self.size
    queue = deque()
    level[s] = 0
    queue.append(s)
    
    while queue:
        u = queue.popleft()
        for edge in self.graph[u]:
            if edge.cap > 0 and level[edge.to] == -1:
                level[edge.to] = level[u] + 1
                queue.append(edge.to)
                if edge.to == t:
                    return level  # 提前终止优化
    return level

阻塞流寻找(DFS with Optimization)

python 复制代码
def dfs_flow(self, u, t, upTo, iter_, level):
    if u == t:
        return upTo
    for i in range(iter_[u], len(self.graph[u])):
        iter_[u] = i  # 当前弧优化
        edge = self.graph[u][i]
        if edge.cap > 0 and level[u] < level[edge.to]:
            d = self.dfs_flow(edge.to, t, min(upTo, edge.cap), iter_, level)
            if d > 0:
                edge.cap -= d
                self.graph[edge.to][edge.rev].cap += d
                return d
    return 0

主算法流程

python 复制代码
def max_flow(self, s, t):
    flow = 0
    while True:
        level = self.bfs_level(s, t)
        if level[t] == -1:  # 无法到达汇点
            return flow
        iter_ = [0] * self.size  # 当前弧数组
        while True:
            f = self.dfs_flow(s, t, float('inf'), iter_, level)
            if f == 0:
                break
            flow += f

最大流最小割定理

割(Cut):将顶点分为 S S S 和 T T T,其中 s ∈ S , t ∈ T s \in S, t \in T s∈S,t∈T

割的容量: c ( S , T ) = ∑ u ∈ S , v ∈ T c ( u , v ) c(S, T) = \sum_{u \in S, v \in T} c(u, v) c(S,T)=∑u∈S,v∈Tc(u,v)

定理:最大流值 = 最小割容量

相关推荐
网硕互联的小客服1 小时前
如何安全配置数据库(MySQL/PostgreSQL/MongoDB)
linux·运维·服务器·网络·windows
一点.点3 小时前
李沐动手深度学习(pycharm中运行笔记)——10.多层感知机+从零实现+简介实现
人工智能·笔记·python·深度学习·pycharm
安全系统学习4 小时前
网络安全之Web渗透加解密
网络·安全·web安全·网络安全·系统安全
枷锁—sha4 小时前
WireShark网络抓包—详细教程
网络·测试工具·web安全·网络安全·wireshark
Ankie Wan4 小时前
tshark的使用技巧(wireshark的命令行,类似tcpdump):转换格式,设置filter
网络·测试工具·wireshark·tcpdump·tshark
武昌库里写JAVA4 小时前
Vue3编译器:静态提升原理
java·开发语言·spring boot·学习·课程设计
Bonnie_12155 小时前
05-jenkins学习之旅-vue前项目部署实践
vue.js·学习·jenkins
moxiaoran57535 小时前
Python学习笔记--Django 表单处理
笔记·python·学习
长流小哥5 小时前
STM32:Modbus通信协议核心解析:关键通信技术
服务器·网络·stm32·单片机·嵌入式硬件·信息与通信·modbus
路过的一个普通人6 小时前
C 语言学习笔记二
c语言·笔记·学习