无向图的最小费用最大循环流问题
字数 5001 2025-12-23 08:01:24

无向图的最小费用最大循环流问题

题目描述

给定一个无向连通图 \(G = (V, E)\),其中每条边 \(e \in E\) 有两个属性:容量 \(c(e) > 0\)(表示该边最多能承载的流量)和单位费用 \(w(e)\)(可正可负,表示沿该边输送一单位流量所产生的成本)。图中没有源点和汇点,也不要求流量守恒。我们的目标是:在图中找到一个“循环流”(即每条边 \(e\) 有一个方向,我们为其分配一个非负流量 \(f(e)\),且 \(f(e) \le c(e)\)),并最小化所有边上的总费用,即 \(\sum_{e \in E} w(e) \cdot f(e)\)。 由于没有流量守恒约束,此问题可以建模为在容量约束下,寻找一个使总费用最小的有向循环流

解题过程

这个问题的关键是将无向图转化为一个有向图网络,使得我们能够利用现有算法(如负权环检测、最小费用流)来求解。下面分步骤讲解。


步骤1:问题转化——将无向边转化为两条有向边

在传统的有向图网络流问题中,每条有向边有明确的容量和费用。但这里我们的图是无向的。为了应用已知算法,我们将每条无向边 \(e = (u, v)\) 拆分为两条方向相反的有向边

  • 一条从 \(u\)\(v\) 的边 \(e_1\),容量为 \(c(e)\),费用为 \(w(e)\)
  • 一条从 \(v\)\(u\) 的边 \(e_2\),容量为 \(c(e)\),费用为 \(w(e)\)

为什么这样做?因为在实际的循环流中,流量可以从 \(u\) 流向 \(v\),也可以从 \(v\) 流向 \(u\),但不能同时双向流动(因为我们最终要赋予每条边一个方向和一个流量值)。不过,我们暂时先允许两条方向边都承载流量,稍后会通过约束保证不会出现双向流动的情况。

现在,我们得到一个有向图 \(D = (V, A)\),其中 \(|A| = 2|E|\)。每条弧 \(a \in A\) 有容量 \(c(a)\) 和费用 \(w(a)\)。目标是找到一个流 \(f: A \to \mathbb{R}_{\ge 0}\),满足:

  1. \(0 \le f(a) \le c(a)\) 对每条弧 \(a \in A\)(容量约束)。
  2. 最小化总费用 \(\sum_{a \in A} w(a) \cdot f(a)\)

注意:这个有向图仍然没有流量守恒约束(即节点的净流入不必为零),所以它是一个非常宽松的模型。


步骤2:引入“不允许双向流动”约束

在原问题中,每条无向边只能选择一个方向来承载流量。但在我们当前的有向图模型中,一条无向边对应的两条反向弧可能同时有正流量(即同时有从 \(u\)\(v\) 和从 \(v\)\(u\) 的流量),这相当于无向边内部有“循环”,会导致无意义的流量和增加不必要的费用。

我们需要添加约束:对于每条原无向边 \(e = (u, v)\) 对应的两条弧 \(a_{uv}\)\(a_{vu}\),必须满足 \(f(a_{uv}) \cdot f(a_{vu}) = 0\),即至少有一个为0。这等价于说,这两条弧上的流量之和不能超过容量 \(c(e)\),且不能两条同时为正。

一个巧妙的处理方法是:将容量约束改为:对于每条无向边 \(e\),两条反向弧的流量之和不超过 \(c(e)\),即 \(f(a_{uv}) + f(a_{vu}) \le c(e)\)。这样,如果两条弧都为正,其和不超过容量,但可能会违反“不能双向”的原则吗?实际上,如果费用为正,同时分配双向流量只会增加总费用,不是最优解;如果费用为负,同时分配双向流量会减少总费用,但我们可以通过检查是否存在负费用有向环来避免这种情况。


步骤3:最优解的结构与负环检测

在没有流量守恒约束、只有容量约束的流问题中,最优解的结构很简单:

  • 如果一条边的费用 \(w(e) > 0\),我们尽量分配 0 流量 以最小化成本。
  • 如果一条边的费用 \(w(e) < 0\),我们尽量分配 最大容量 \(c(e)\) 的流量,因为负费用意味着“输送流量能赚钱”,我们想尽可能多输送。
  • 但要注意:我们不能独立决定每条边,因为流量必须形成一个循环(即最终分配给每条边一个方向,并满足图作为一个整体是循环的)。实际上,我们可以证明:最优解一定可以表示为若干个有向环的叠加,每个环上的边方向一致,且环上每条边要么流量为0,要么为满容量。

更形式化地,我们可以将问题重述为:
寻找一个集合的有向环,每个环有一个流量值,环上的边方向一致,且每个环的流量乘以环上边的费用之和为负(否则加入该环会增加总费用)。我们想尽可能多地输送负费用环上的流量,直到某条边达到容量上限。

因此,算法思路是:

  1. 从零流开始。
  2. 在有向图 \(D\) 中,寻找一个负费用有向环(即环上所有边的费用之和为负)。
  3. 如果能找到这样的环,就尽可能多地增加该环上的流量(增加量受环上最小剩余容量限制)。
  4. 重复步骤2-3,直到找不到负费用有向环为止。此时得到最小费用循环流。

为什么?因为增加一个负费用环的流量会降低总费用,而无法再找到负费用环时,说明已达到局部最优(实际上也是全局最优,类似于最小费用流中的“负环最优性定理”)。


步骤4:算法实现细节

我们可以用 Bellman-Ford 算法(或其改进版本)来检测负环。但需要注意:我们的图允许负权边,且没有源点,所以不能直接运行单源最短路径算法。常用的方法是:

  1. 在图中添加一个超级源点 \(s\),从 \(s\) 向所有其他节点连一条费用为0、容量为无穷大的边。
  2. \(s\) 为源点,用 SPFA(Shortest Path Faster Algorithm)或带负环检测的 Bellman-Ford 计算最短路径距离 \(dist[v]\)
  3. 根据距离 \(dist[v]\) 调整边的费用(类似于最小费用流中的“势能”方法),得到非负费用的图,然后在此图上找负环? 等等,这里有点微妙。

实际上,更直接的方法是:

  • 我们维护当前流 \(f\)
  • 根据 \(f\) 定义残量网络:每条弧 \(a\) 如果 \(f(a) < c(a)\),则保留其原有方向,剩余容量为 \(c(a) - f(a)\),费用为 \(w(a)\);如果 \(f(a) > 0\),则添加一条反向弧,容量为 \(f(a)\),费用为 \(-w(a)\)(表示退流可减少费用)。
  • 在残量网络中找负费用有向环。若找到,则沿环增广。

步骤5:具体步骤举例

假设有一个无向三角形图,顶点 \(\{1, 2, 3\}\),三条边:

  • \((1,2): c=3, w=2\)(正费用)
  • \((2,3): c=4, w=-1\)(负费用)
  • \((3,1): c=2, w=1\)(正费用)

步骤5.1 转化为有向图:
每条无向边变成两条有向弧,共6条弧,容量分别为3,3,4,4,2,2,费用分别为2,2,-1,-1,1,1。

步骤5.2 初始流 \(f = 0\)

步骤5.3 构建初始残量网络:就是原图的所有弧,剩余容量等于原容量,费用不变。

步骤5.4 找负费用环:
\(2 \to 3 \to 1 \to 2\)(对应弧 \((2,3)\), \((3,1)\), \((1,2)\) 方向)费用和为 \((-1) + 1 + 2 = 2 > 0\),不是负环。
\(2 \to 1 \to 3 \to 2\)(对应弧 \((2,1)\), \((1,3)\), \((3,2)\) 方向)费用和为 \(2 + 1 + (-1) = 2 > 0\),也不是负环。
\(1 \to 3 \to 2 \to 1\)(对应弧 \((1,3)\), \((3,2)\), \((2,1)\) 方向)费用和为 \(1 + (-1) + 2 = 2 > 0\)
看起来没有负环?等等,我们忽略了一个简单环: \(2 \to 3\)\(3 \to 2\) 是一个长度为2的环,但它们是同一条无向边的反向弧,在原问题中不允许同时为正。不过,在我们的残量网络中,允许这样的“双向”环吗?如果我们尝试增加 \((2,3)\)\((3,2)\) 上的流量,实际上相当于在原无向边 \((2,3)\) 上同时分配双向流量,这虽然可能降低总费用(因为费用为负),但违反原问题约束。所以,我们必须在构建残量网络时,避免出现这种“同一条无向边两条弧都在环中”的情况。

因此,我们需要修改残量网络的定义:对于每条无向边 \(e = (u,v)\) 对应的两条弧 \(a_{uv}\)\(a_{vu}\),如果当前 \(f(a_{uv}) + f(a_{vu}) < c(e)\),则可以选择其中一条弧增加流量(但不能同时选择两条)。这可以通过在找环时添加约束来实现,但实现起来较复杂。

实际上,更常见的做法是:将无向边看作两个节点之间的一条“可双向流动”的边,但流量净值为 \(f_{uv} - f_{vu}\),且要求 \(|f_{uv} - f_{vu}| \le c(e)\)。这样,我们可以将问题转化为一个带上下界的网络流问题,但这里不展开。

对于本例,直观最优解是:在负费用边 \((2,3)\) 上尽可能多输送流量,但由于需要形成循环,它必须和另外两条边一起构成环。实际上,环 \(1 \to 2 \to 3 \to 1\) 上,边 \((1,2)\)\((3,1)\) 费用为正,所以输送流量会增加成本;因此,最优解可能就是零流,总费用为0。


步骤6:算法总结

  1. 输入:无向图 \(G=(V,E)\),每条边容量 \(c(e)\),费用 \(w(e)\)
  2. 转化:构建有向图 \(D=(V,A)\),每条无向边对应两条反向弧,容量均为 \(c(e)\),费用均为 \(w(e)\)
  3. 初始化:流 \(f = 0\)
  4. 重复
    • 构建残量网络:对每条弧 \(a \in A\),如果 \(f(a) < c(a)\),则保留正向弧,剩余容量 \(c(a)-f(a)\),费用 \(w(a)\);如果 \(f(a) > 0\),则添加反向弧,容量 \(f(a)\),费用 \(-w(a)\)
    • 在残量网络中,运行 Bellman-Ford 或 SPFA 检测是否存在负费用有向环(注意:要避免检测到长度为2的“双向弧环”,这可通过标记每条无向边,确保环中不会同时包含同一无向边的两条弧)。
    • 如果找到负费用环 \(C\),则计算环上最小剩余容量 \(\Delta = \min_{a \in C} residual\_capacity(a)\)。然后,沿环增加流量 \(\Delta\)(正向弧流量增加 \(\Delta\),反向弧流量减少 \(\Delta\))。
  5. 直到残量网络中无负费用环。
  6. 输出:最终流 \(f\),总费用 \(\sum_{a \in A} w(a) \cdot f(a)\)

复杂度:每次找负环需 \(O(|V||A|)\) 时间,最多增广 \(O(|V| \cdot \max c(e))\) 次(如果容量为整数),但通常用 scaling 技术优化。实践中,该算法在中小规模图上可行。


通过以上步骤,我们逐步将无向图的最小费用最大循环流问题,转化为有向图的负环检测与增广问题,从而得到最优解。

无向图的最小费用最大循环流问题 题目描述 给定一个无向连通图 \( G = (V, E) \),其中每条边 \( e \in E \) 有两个属性:容量 \( c(e) > 0 \)(表示该边最多能承载的流量)和单位费用 \( w(e) \)(可正可负,表示沿该边输送一单位流量所产生的成本)。图中没有源点和汇点, 也不要求流量守恒 。我们的目标是:在图中找到一个“循环流”(即每条边 \( e \) 有一个方向,我们为其分配一个非负流量 \( f(e) \),且 \( f(e) \le c(e) \)),并 最小化所有边上的总费用 ,即 \( \sum_ {e \in E} w(e) \cdot f(e) \)。 由于没有流量守恒约束,此问题可以建模为在容量约束下,寻找一个使总费用最小的 有向循环流 。 解题过程 这个问题的关键是将无向图转化为一个有向图网络,使得我们能够利用现有算法(如负权环检测、最小费用流)来求解。下面分步骤讲解。 步骤1:问题转化——将无向边转化为两条有向边 在传统的有向图网络流问题中,每条有向边有明确的容量和费用。但这里我们的图是无向的。为了应用已知算法,我们将每条无向边 \( e = (u, v) \) 拆分为 两条方向相反的有向边 : 一条从 \( u \) 到 \( v \) 的边 \( e_ 1 \),容量为 \( c(e) \),费用为 \( w(e) \)。 一条从 \( v \) 到 \( u \) 的边 \( e_ 2 \),容量为 \( c(e) \),费用为 \( w(e) \)。 为什么这样做?因为在实际的循环流中,流量可以从 \( u \) 流向 \( v \),也可以从 \( v \) 流向 \( u \),但 不能同时双向流动 (因为我们最终要赋予每条边一个方向和一个流量值)。不过,我们暂时先允许两条方向边都承载流量,稍后会通过约束保证不会出现双向流动的情况。 现在,我们得到一个有向图 \( D = (V, A) \),其中 \( |A| = 2|E| \)。每条弧 \( a \in A \) 有容量 \( c(a) \) 和费用 \( w(a) \)。目标是找到一个流 \( f: A \to \mathbb{R}_ {\ge 0} \),满足: \( 0 \le f(a) \le c(a) \) 对每条弧 \( a \in A \)(容量约束)。 最小化总费用 \( \sum_ {a \in A} w(a) \cdot f(a) \)。 注意:这个有向图仍然 没有流量守恒约束 (即节点的净流入不必为零),所以它是一个非常宽松的模型。 步骤2:引入“不允许双向流动”约束 在原问题中,每条无向边只能选择一个方向来承载流量。但在我们当前的有向图模型中,一条无向边对应的两条反向弧可能同时有正流量(即同时有从 \( u \) 到 \( v \) 和从 \( v \) 到 \( u \) 的流量),这相当于无向边内部有“循环”,会导致无意义的流量和增加不必要的费用。 我们需要添加约束:对于每条原无向边 \( e = (u, v) \) 对应的两条弧 \( a_ {uv} \) 和 \( a_ {vu} \),必须满足 \( f(a_ {uv}) \cdot f(a_ {vu}) = 0 \),即至少有一个为0。这等价于说,这两条弧上的流量之和不能超过容量 \( c(e) \),且不能两条同时为正。 一个巧妙的处理方法是: 将容量约束改为 :对于每条无向边 \( e \),两条反向弧的流量之和不超过 \( c(e) \),即 \( f(a_ {uv}) + f(a_ {vu}) \le c(e) \)。这样,如果两条弧都为正,其和不超过容量,但可能会违反“不能双向”的原则吗?实际上,如果费用为正,同时分配双向流量只会增加总费用,不是最优解;如果费用为负,同时分配双向流量会减少总费用,但我们可以通过检查是否存在 负费用有向环 来避免这种情况。 步骤3:最优解的结构与负环检测 在没有流量守恒约束、只有容量约束的流问题中,最优解的结构很简单: 如果一条边的费用 \( w(e) > 0 \),我们尽量分配 0 流量 以最小化成本。 如果一条边的费用 \( w(e) < 0 \),我们尽量分配 最大容量 \( c(e) \) 的流量,因为负费用意味着“输送流量能赚钱”,我们想尽可能多输送。 但要注意:我们不能独立决定每条边,因为流量必须形成一个循环(即最终分配给每条边一个方向,并满足图作为一个整体是循环的)。实际上,我们可以证明:最优解一定可以表示为若干个 有向环的叠加 ,每个环上的边方向一致,且环上每条边要么流量为0,要么为满容量。 更形式化地,我们可以将问题重述为: 寻找一个集合的有向环,每个环有一个流量值,环上的边方向一致,且每个环的流量乘以环上边的费用之和为负(否则加入该环会增加总费用)。我们想尽可能多地输送负费用环上的流量,直到某条边达到容量上限。 因此,算法思路是: 从零流开始。 在有向图 \( D \) 中,寻找一个 负费用有向环 (即环上所有边的费用之和为负)。 如果能找到这样的环,就尽可能多地增加该环上的流量(增加量受环上最小剩余容量限制)。 重复步骤2-3,直到找不到负费用有向环为止。此时得到最小费用循环流。 为什么?因为增加一个负费用环的流量会降低总费用,而无法再找到负费用环时,说明已达到局部最优(实际上也是全局最优,类似于最小费用流中的“负环最优性定理”)。 步骤4:算法实现细节 我们可以用 Bellman-Ford 算法 (或其改进版本)来检测负环。但需要注意:我们的图允许负权边,且没有源点,所以不能直接运行单源最短路径算法。常用的方法是: 在图中添加一个 超级源点 \( s \) ,从 \( s \) 向所有其他节点连一条费用为0、容量为无穷大的边。 以 \( s \) 为源点,用 SPFA(Shortest Path Faster Algorithm)或带负环检测的 Bellman-Ford 计算最短路径距离 \( dist[ v ] \)。 根据距离 \( dist[ v] \) 调整边的费用(类似于最小费用流中的“势能”方法),得到 非负费用 的图,然后在此图上找负环? 等等,这里有点微妙。 实际上,更直接的方法是: 我们维护当前流 \( f \)。 根据 \( f \) 定义 残量网络 :每条弧 \( a \) 如果 \( f(a) < c(a) \),则保留其原有方向,剩余容量为 \( c(a) - f(a) \),费用为 \( w(a) \);如果 \( f(a) > 0 \),则添加一条反向弧,容量为 \( f(a) \),费用为 \( -w(a) \)(表示退流可减少费用)。 在残量网络中找负费用有向环。若找到,则沿环增广。 步骤5:具体步骤举例 假设有一个无向三角形图,顶点 \( \{1, 2, 3\} \),三条边: \( (1,2): c=3, w=2 \)(正费用) \( (2,3): c=4, w=-1 \)(负费用) \( (3,1): c=2, w=1 \)(正费用) 步骤5.1 转化为有向图: 每条无向边变成两条有向弧,共6条弧,容量分别为3,3,4,4,2,2,费用分别为2,2,-1,-1,1,1。 步骤5.2 初始流 \( f = 0 \)。 步骤5.3 构建初始残量网络:就是原图的所有弧,剩余容量等于原容量,费用不变。 步骤5.4 找负费用环: 环 \( 2 \to 3 \to 1 \to 2 \)(对应弧 \( (2,3) \), \( (3,1) \), \( (1,2) \) 方向)费用和为 \( (-1) + 1 + 2 = 2 > 0 \),不是负环。 环 \( 2 \to 1 \to 3 \to 2 \)(对应弧 \( (2,1) \), \( (1,3) \), \( (3,2) \) 方向)费用和为 \( 2 + 1 + (-1) = 2 > 0 \),也不是负环。 环 \( 1 \to 3 \to 2 \to 1 \)(对应弧 \( (1,3) \), \( (3,2) \), \( (2,1) \) 方向)费用和为 \( 1 + (-1) + 2 = 2 > 0 \)。 看起来没有负环?等等,我们忽略了一个简单环: \( 2 \to 3 \) 和 \( 3 \to 2 \) 是一个长度为2的环,但它们是同一条无向边的反向弧,在原问题中不允许同时为正。不过,在我们的残量网络中,允许这样的“双向”环吗?如果我们尝试增加 \( (2,3) \) 和 \( (3,2) \) 上的流量,实际上相当于在原无向边 \( (2,3) \) 上同时分配双向流量,这虽然可能降低总费用(因为费用为负),但违反原问题约束。所以,我们必须在构建残量网络时,避免出现这种“同一条无向边两条弧都在环中”的情况。 因此,我们需要修改残量网络的定义:对于每条无向边 \( e = (u,v) \) 对应的两条弧 \( a_ {uv} \) 和 \( a_ {vu} \),如果当前 \( f(a_ {uv}) + f(a_ {vu}) < c(e) \),则可以选择其中一条弧增加流量(但不能同时选择两条)。这可以通过在找环时添加约束来实现,但实现起来较复杂。 实际上,更常见的做法是:将无向边看作两个节点之间的一条“可双向流动”的边,但流量净值为 \( f_ {uv} - f_ {vu} \),且要求 \( |f_ {uv} - f_ {vu}| \le c(e) \)。这样,我们可以将问题转化为一个带上下界的网络流问题,但这里不展开。 对于本例,直观最优解是:在负费用边 \( (2,3) \) 上尽可能多输送流量,但由于需要形成循环,它必须和另外两条边一起构成环。实际上,环 \( 1 \to 2 \to 3 \to 1 \) 上,边 \( (1,2) \) 和 \( (3,1) \) 费用为正,所以输送流量会增加成本;因此,最优解可能就是零流,总费用为0。 步骤6:算法总结 输入 :无向图 \( G=(V,E) \),每条边容量 \( c(e) \),费用 \( w(e) \)。 转化 :构建有向图 \( D=(V,A) \),每条无向边对应两条反向弧,容量均为 \( c(e) \),费用均为 \( w(e) \)。 初始化 :流 \( f = 0 \)。 重复 : 构建残量网络:对每条弧 \( a \in A \),如果 \( f(a) < c(a) \),则保留正向弧,剩余容量 \( c(a)-f(a) \),费用 \( w(a) \);如果 \( f(a) > 0 \),则添加反向弧,容量 \( f(a) \),费用 \( -w(a) \)。 在残量网络中,运行 Bellman-Ford 或 SPFA 检测是否存在负费用有向环(注意:要避免检测到长度为2的“双向弧环”,这可通过标记每条无向边,确保环中不会同时包含同一无向边的两条弧)。 如果找到负费用环 \( C \),则计算环上最小剩余容量 \( \Delta = \min_ {a \in C} residual\_capacity(a) \)。然后,沿环增加流量 \( \Delta \)(正向弧流量增加 \( \Delta \),反向弧流量减少 \( \Delta \))。 直到 残量网络中无负费用环。 输出 :最终流 \( f \),总费用 \( \sum_ {a \in A} w(a) \cdot f(a) \)。 复杂度 :每次找负环需 \( O(|V||A|) \) 时间,最多增广 \( O(|V| \cdot \max c(e)) \) 次(如果容量为整数),但通常用 scaling 技术优化。实践中,该算法在中小规模图上可行。 通过以上步骤,我们逐步将无向图的最小费用最大循环流问题,转化为有向图的负环检测与增广问题,从而得到最优解。