图与网络——最小费用最大流Python实现

最小费用最大流问题是经济学和管理学中的一类典型问题。在一个网络中每段路径都有“容量”和“费用”两个限制的条件下,此类问题的研究试图寻找出:流量从A到B,如何选择路径、分配经过路径的流量,可以在流量最大的前提下,达到所用的费用最小的要求。如n辆卡车要运送物品,从A地到B地。由于每条路段都有不同的路费要缴纳,每条路能容纳的车的数量有限制,最小费用最大流问题指如何分配卡车的出发路径可以达到费用最低,物品又能全部送到。

一、最小费用最大流问题

容量网络:图D=(V,A,C)

  • V:点集。其中 vs为发点,只有发出的弧;vt为收点,该点只有进入的弧;其余的点为中间点;
  • A: 弧集。对于每一条弧 (vi,vj)A
  • C:容量集。每一条弧的容量c(vi,vj)>=0(或简记为 cij),其中C={cij}
  • f: fij=f(vi,vj):弧 (vi,vj)上的流量

可行流:

  • 容量限制条件:0fijij
  • 平衡条件:中间点:流出量 = 流入量   j:(vi,vj)Afijk:(vk,vi)Afki=0
    发点:

j:(vs,vj)Afsj=v

收点:

k:(vk,vt)Afkt=v

式中:v称为这个可行流的流量,即发点的净输出量。

可行流的费用:设每条弧单位流量的费用记为bij,可行流f费用为

b(f)=(vi,vj)bijfij

最小费用最大流问题就是在网络中求一个最大流f,使流的总输送费用b(f)最小。
增流网络:f是网络 D=(V,A,C,F,B)的一个网络流,按照以下规则构建一个新的网络 Df=(V,A,C,B),该网络称为伴随f的增流网络,其中V为顶点集,A为弧集,C为容量集,F为流量集,B为费用集。

  • 顶点:网络DfD 的顶点与网络的顶点相同;

  • 弧与权:

    • D中的弧(vi,vj)若为零流弧,即fij=0,则在Df中构建一条同向的弧,cij=cijfijbij=bij
    • 在D中的弧(vi,vj)若为饱和弧,即 fij=cij,则在Df中构建一条反向的弧cij=_ijbij=bij
    • 在D中的弧(vi,vj)若为非饱和弧,即fij<cij,则在Df中分别构建一条同向的弧和一条反向的弧,同向的弧 cij=cijfijbij=bij;反向的弧 cij=fijbij=bij
  • 负回路:在增流网络Df​中,所有的权(费用)之和小于零的回路称为负回路。

  • 增流圈:在增流网络 Df​中的负回路对应网络D中的一个圈,在这个圈中,如果方向与这个负回路方向相同的所有弧都为不饱和弧,方向与负回路方向相反的所有弧都为非零流弧,则这个圈称为增流圈。

最大流问题的线性规划模型:

maxv s.t. {j:(vi,vj)Afijj:(vj,vi)Afji={v,i=sv,i=t0,is,t0fij,(vi,vj)A

最小费用最大流问题的数学模型:

min(vi,vj)Abijfij s.t. {j:(vi,vj)Afijj:(vj,vi)Afji={v,i=sv,i=t0,is,t0fij,(vi,vj)Af

二、最小费用最大流的算法

在这里插入图片描述

2.1 求得最大流量调整流量达到最小费用

利用最大流算法,将网络的流量调整到最大流
构建伴随网络流f的增流网络Df
在增流网络Df 中,查找关于费用的负回路,令θ=min{cij},(cij为负回路中各弧的容量),若不存在负回路,则说明当前网络流已经是最小费用流,结束算法。
针对负回路对应网络D中的圈,若该圈是增流圈,则把增流圈方向上与负回路方向一致的所有弧的流量加上θ,把增流圈方向上与负回路方向相反的所有弧的流量减去θ;若该圈不是增流圈,则转到步骤3重新寻找负回路。

2.2 寻找最小费用增广链达到最大流量

从网络D的零流f开始,构建伴随网络流f的增流网络Df(此处Df 中的权只需要费用cij​)
在增流网络Df中用最短路径算法寻找从源到汇的最短路径,则该最短路径即对应网络D中的一条最小费用增广链;若找不到从源到汇的最短路,说明已经得到最大流,结束算法
在网络D中调整流量。前向弧上令θj=cijfij,后向弧上令 θj=fij​ ,调整量 θ=minθj
重复步前面骤,直到在增流网络Df 中找不到从源到汇的最短路

三、最小费用最大流Pyhton程序

案例:给出下图网络的最小费用最大流(Minimum Cost Maximum Flow,MCMF)。


图中(12,7)第1个数字表示弧的容量,第2个数字表示流过单位流量所需的成本。

import numpy as np
import matplotlib.pyplot as plt # 导入 Matplotlib 工具包
import networkx as nx  # 导入 NetworkX 工具包

# 3. 最小费用最大流问题(Minimum Cost Maximum Flow,MCMF)
# 创建有向图
G3 = nx.DiGraph()  # 创建一个有向图 DiGraph
G3.add_edges_from([('s','v1',{'capacity': 13, 'weight': 7}),
                  ('s','v2',{'capacity': 9, 'weight': 9}),
                  ('v1','v3',{'capacity': 6, 'weight': 6}),
                  ('v1','v4',{'capacity': 5, 'weight': 5}),
                  ('v2','v1',{'capacity': 4, 'weight': 4}),
                  ('v2','v3',{'capacity': 5, 'weight': 2}),
                  ('v2','v5',{'capacity': 5, 'weight': 5}),
                  ('v3','v4',{'capacity': 5, 'weight': 2}),
                  ('v3','v5',{'capacity': 4, 'weight': 1}),
                  ('v3','t',{'capacity': 4, 'weight': 4}),
                  ('v4','t', {'capacity': 9, 'weight': 7}),
                  ('v5','t',{'capacity': 9, 'weight': 5})]) # 添加边的属性 'capacity', 'weight'

# 求最小费用最大流
minCostFlow = nx.max_flow_min_cost(G3, 's', 't')  # 求最小费用最大流
minCost = nx.cost_of_flow(G3, minCostFlow)  # 求最小费用的值
maxFlow = sum(minCostFlow['s'][j] for j in minCostFlow['s'].keys())  # 求最大流量的值

# # 数据格式转换
edgeLabel1 = nx.get_edge_attributes(G3,'capacity')  # 整理边的标签,用于绘图显示
edgeLabel2 = nx.get_edge_attributes(G3,'weight')
edgeLabel={}
for i in edgeLabel1.keys():
    edgeLabel[i]=f'({edgeLabel1[i]:},{edgeLabel2[i]:})'  # 边的(容量,成本)
edgeLists = []
for i in minCostFlow.keys():
    for j in minCostFlow[i].keys():
        edgeLabel[(i, j)] += ',f=' + str(minCostFlow[i][j])  # 将边的实际流量添加到 边的标签
        if minCostFlow[i][j]>0:
            edgeLists.append((i,j))

print("最小费用最大流的路径及流量: ", minCostFlow)  # 输出最大流的途径和各路径上的流量
print("最小费用最大流的路径:", edgeLists)  # 输出最小费用最大流的途径
print("最大流量: ", maxFlow)  # 输出最大流量的值
print("最小费用: ", minCost)  # 输出最小费用的值
最小费用最大流的路径及流量:  {'s': {'v1': 11, 'v2': 9}, 'v1': {'v3': 6, 'v4': 5}, 'v2': {'v1': 0, 'v3': 4, 'v5': 5}, 'v3': {'v4': 2, 'v5': 4, 't': 4}, 'v4': {'t': 7}, 'v5': {'t': 9}, 't': {}}
最小费用最大流的路径: [('s', 'v1'), ('s', 'v2'), ('v1', 'v3'), ('v1', 'v4'), ('v2', 'v3'), ('v2', 'v5'), ('v3', 'v4'), ('v3', 'v5'), ('v3', 't'), ('v4', 't'), ('v5', 't')]
最大流量:  20
最小费用:  370

参考文献

  1. 网络流——最大流和最小费用流
  2. 最小费用最大流问题详解
  3. Python小白的数学建模课-19.网络流优化问题
posted @   郝hai  阅读(1546)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
历史上的今天:
2022-04-23 R语言基础操作之入门篇
点击右上角即可分享
微信分享提示