在大规模战争中,后勤补给是重中之重,为了尽最大可能满足前线的物资消耗,后勤部队必然要充分利用每条运输网。与此同时,交战双方也想要以最小的代价切断敌军的补给,从而使敌军处于孤立无援的境地。在古今中外的各种重大战役中,上演了一幕幕补给线上的攻防战。

甲军的运输路线

  假设甲、乙两军正在交战,图8.17是甲军的补给运输网,其中t是甲军的前沿阵地,s是后勤大营,每条边是一条公路,边上的数字代表公路的宽度。

  如果甲军想要尽最大努力供应前线的消耗,应该怎样设计运输路线?

  这个问题很容易规约成网络流模型,使用下面的代码可以直接计算出结果。

 1 import network_flow as nf
 2
 3 V = [0, 1, 2, 3, 4, 5, 6, 7, 8]
 4 E = [nf.Edge(0, 1, 15), nf.Edge(0, 2, 15), nf.Edge(0, 3, 15), nf.Edge(1, 4, 2), nf.Edge(2, 4, 3),
 5      nf.Edge(2, 5, 2), nf.Edge(3, 5, 4), nf.Edge(4, 5, 2), nf.Edge(4, 6, 2), nf.Edge(5, 6, 4),
 6      nf.Edge(5, 7, 3), nf.Edge(6, 8, 15), nf.Edge(7, 8, 15)]
 7 s, t = 0, 8
 8 G = nf.Network(V, E, s, t)
 9 ford_fullkerson = nf.FordFulkerson(G)
10 ford_fullkerson.start()
11 ford_fullkerson.display()
12 X, Y, st_cut = ford_fullkerson.min_st_cut()
13 ford_fullkerson.display_st_cut(X, Y, st_cut)

  (network_flow参考上一章的相关代码)运行结果对应的网络流:

乙军的轰炸目标

  甲军想要充分利用每条公路,乙军的目的正好相反,是破坏公路网,使乙军的战斗部队处于孤立无援的境地。乙军打算组织一次针对甲军补给线的战略轰炸,由于甲军在每个节点都部署了大量防空武器,因此需要绕过节点,直接轰炸防御薄弱的公路。假设炸掉容量为1的公路需要n颗炸弹,破坏的公路容量和投掷的炸弹数成正比,怎样设计轰炸目标才能以最小的代价完全破坏敌军的补给线?

  一个方案是炸毁直接通向汇点的公路,但由于连接汇点的两条公路太宽,完全破坏需要30n的炸弹,这显然不是最小代价。如果换个地点,假设轰炸的是v5→v7,那么只需要3n的炸弹就可以使宽敞的v7→t沦为摆设。为了设计这种轰炸方案,需要理解最小st-剪切的概念。

8.3.3 最小st-剪切

  设计成本最低的轰炸方案是我们的目标,直接寻找起来比较困难,幸而这个目标与网络的最小剪切有密切关系。

  一个流网络的顶点可以划分成两个不相交的集合XY,源点s和汇点t分属于这两个集合,连接XY的边称为这个流网络的st-剪切(st-cut,也称为截、割或切割)。我们用浅色圆圈表示包含源点的集合X,深色圆圈表示包含汇点的集合Y,这样就很容易看出一个流网络的st-剪切:

  既然st-剪切是边的集合,那么集合中边的容量之和就是st-剪切的容量。一个流网络有很多种不同的st-剪切,其中容量最小的一个就是最小st-剪切。

  st-剪切包含了所有源点到汇点的通道,一个显而易见的结论是:st-剪切的流值等于这个网络流的值。更进一步,任何网络流的值都不会超过st-剪切的容量,这也意味着st-剪切代表着流网络的瓶颈,最小st-剪切的容量不会小于最大流的值,这个定理称为最大流-最小剪切定理。该定理也可以反过来表述:网络流的值最大不会大于任意一个给定的st-剪切的容量。当X只包含源点或Y只包含汇点时,最大流-最小剪切定理最为直观。

  最小st-剪切代表补给线上最难走或最重要的路段,只要破坏这些路段,就能以最小的代价掐断敌军的补给,即使只破坏了一部分,也能有效降低敌军的补给能力。既然最小st-剪切和最大流存在关联关系,我们就可以在寻找最大流时顺带找出最小st-剪切,这仍然需要使用残存网。在残存网中,将源点和从源点出发可以到达的顶点看作集合X,剩下的顶点看作集合Y,对于边vw,如果满足v属于Xw属于Y,那么vw就是最小st-剪切中的一条边。

  以下图为例,在残存网中源点能够到达的顶点只有v3,原网络的最小st-剪切是:

  可以根据这种思路在FordFulkerson中添加寻找最小st-剪切的实现。

 1 class FordFulkerson():
 2     def __init__(self, G:Network):
 3         self.G = G
 4         self.max_flow = 0  # 最大流
 5     …… (省略部分参考上一章的相关代码)
 6     def min_st_cut(self):
 7         ''' 找到最小st-剪切 '''
 8         X = [self.G.s] # st-剪切的X集合
 9         stack = [self.G.s]
10         while len(stack) > 0:
11             v = stack.pop()
12             for e in  self.G.edges_from(v): # 所有从v顶点流出的边
13                 if e.w != self.G.t and e.w not in X and  e.residual_cap_to(e.w) > 0:
14                     X.append(e.w)
15                     stack.append(e.w)
16         Y = list(set(self.G.V) - set(X)) # st-剪切的X集合
17         st_cut = [e for e in self.G.E if e.v in X and e.w in Y] # 连接X和Y的边
18         return X, Y, st_cut
19
20     def display_st_cut(self, X, Y, st_cut):
21         print('X={0}, Y={1}'.format(X, Y))
22         print('st-cut={}'.format([str(e) for e in st_cut]))

  min_st_cut使用深度优先搜索寻找最小st-剪切。由于这种方法需要借助残存网,因此在使用min_st_cut前需要首先执行一次计算最大流的操作。现在可以计算出乙军的轰炸目标了:

姜子牙的押粮官

  在《封神演义》中,姜子牙经过金台拜将之后,担任“扫荡成汤天宝大元帅”一职,代武王伐纣。率领六十万西岐大军浩浩荡荡,东进朝歌。所谓“三军未动,粮草先行”,在临行前,姜子牙任命了四个先锋官的同时,又任命了杨戬、土行孙、郑伦三个押粮官。

  押粮前必先征粮,单从一个地方征粮恐怕不足以支持一场灭国战争,假设下图是西岐的粮道。

  边的容量代表粮道的运力,杨戬、土行孙、郑伦分别从三v1v2v3个征粮地同时出发,将粮草运往唯一的前沿阵地t,由于运粮过程中十分安全,所以三人可以在每个节点处合兵或分兵,怎样行进才能使粮道发挥出最大运力呢?

多个源点与多个汇点

  问题可以规约成典型的最大流问题,但与之前介绍的st-网络不同,粮道图中有多个源点(或者说没有源点),如此一来将会对最大流的相关算法造成影响,怎么办呢?

  其实很简单,在三个源点前再加入一个超级源点,这样一来v1v2v3就变成了普通的节点,它们也符合守恒定律,原网络也转换成了st-网:

  与此类似,也可以通过建立一个超级汇点来处理多个汇点的情况。

粮道的最大运力

  有了超级节点后,只要把初始数据输入交给计算机就可以了。

 1 import network_flow as nf
 2
 3 V = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
 4 E = [nf.Edge(0, 1, 18), nf.Edge(0, 2, 18), nf.Edge(0, 3, 18), nf.Edge(1, 4, 9),
 5      nf.Edge(1, 5, 9), nf.Edge(2, 5, 9), nf.Edge(2, 6, 9), nf.Edge(3, 6, 9),
 6      nf.Edge(3, 7, 9), nf.Edge(4, 8, 3), nf.Edge(4, 9, 12), nf.Edge(5, 9, 6),
 7      nf.Edge(5, 10, 14), nf.Edge(6, 10, 7), nf.Edge(6, 11, 5), nf.Edge(7, 11, 10),
 8      nf.Edge(7, 12, 12), nf.Edge(8, 13, 8), nf.Edge(9, 13, 8), nf.Edge(10, 13, 8),
 9      nf.Edge(11, 13, 8), nf.Edge(12, 13, 8)]
10 s, t = 0, 13
11 G = nf.Network(V, E, s, t)
12 ford_fullkerson = nf.FordFulkerson(G)
13 ford_fullkerson.start()
14 ford_fullkerson.display()

  最大流是33,下图是根据程序运行结果映射的网络流。

  最大流是确定的,但押粮路线并不是唯一的,最大流算法和边的输入顺序都会对它产生影响。对于增广路径最大流算法来说,寻找增广路径的算法也会影响最终的押粮路线。

  


   作者:我是8位的

  出处:http://www.cnblogs.com/bigmonkey

  本文以学习、研究和分享为主,如需转载,请联系本人,标明作者和出处,非商业用途!

  扫描二维码关注公众号“我是8位的”

转载于:https://www.cnblogs.com/bigmonkey/p/11010891.html

网络流(3)——找到最小st-剪切相关推荐

  1. js数组查找最接近_在JavaScript数组中找到最小元素的位置

    在JavaScript数组中找到最小元素的位置 注*  之前有篇文章介绍过数据遍历的性能比较: for in 比for loop慢至少20倍 ,这是另外一篇比较数组查找性能的例子,通过对手工/inde ...

  2. Minimum Coins(找到最小数量的硬币)

    中文标题[找到最小数量的硬币] 题目的要求比较简单,要求找到最小数量的硬币. 给定的硬币数量是 1,3, 5 英文描述 英文题目的要求请参考下图: 中文描述 主要要求是你手上已经有 1,3,5 面值的 ...

  3. 网络流 最大流 最小割 费用流

    [腾讯文档]网络流初步 网络流初步 文章目录 网络流初步 一.网络流简介 1. 网络 2. 流 3. 再次理解网络流 二.常见题型(三种) 三.相关问题对应算法介绍 1.最大流 (1) FF算法 - ...

  4. [网络流24题]最小路径覆盖问题

    题目描述 对于一个路径覆盖会有两个性质: 1.每个点属于且只属于一条路径: 2.在每条路径中,除终点外,每个点只有一条边可以通向路径中的另外一个点. 所以可以把每个点拆成两个点,一个是起始点,一个是目 ...

  5. P2774-方格取数问题【网络流,最大流,最小割】

    正题 链接: https://www.luogu.org/problemnew/show/P2774 题意 在一个n*m的数字矩阵中取数,取得数不能相邻,求能取到的最大价值. 解题思路 最大价值,那么 ...

  6. 4个数字,如何最快找到最小的2个数

    有A.B.C.D 4个数字,如何比较才能用最小的逻辑资源得到其中最小的2个数,且要知道这2个数的大小顺序. 可以先从A.B,C.D中选出最小的,比如A.C.然后A和C比较得到最小的,比如A.然后C和B ...

  7. 网络流24题 最小路径覆盖问题

    Description 问题描述: 给定有向图G=(V,E).设P 是G 的一个简单路(顶点不相交)的集合.如果V 中每个顶点恰好在P 的一条路上,则称P是G 的一个路径覆盖.P 中路径可以从V 的任 ...

  8. C#找到最小的整数X,同时满足:X是2019的整倍数,X的每一位数字是奇数

    class Program{static void Main(string[] args){int num = 2019;while (true){if (num%2019==0&&I ...

  9. AcWing2279 网络战争 (01分数规划+网络流 最小割模型)

    原题链接:AcWing2279 网络战争 题目大意 给一个无向带权图,求将s和t分开的一个边割集,使得割集的平均边权最小,即最小化∑e∈cwe∣c∣\frac{\sum_{e\in c} w_e}{| ...

最新文章

  1. sklearn gridcv
  2. 获取错误:当试图让pgsql使用rails时,用户“postgres”的对等身份验证失败
  3. Modular Multiplicative Inverse(模乘逆元)
  4. JZOJ 5956. 【NOIP2018模拟11.7A组】easy LCA
  5. 这些表情包你有吗?来 Battle 啊
  6. 辅助Visual Studio 2017部署的DevOps新工具
  7. python代码导出_代码生成 – Python生成Python
  8. 第三回 Bootstrap3.x 起步
  9. 基于SOC方案的嵌入式开发-远程定时设备
  10. Java大数类自我需要掌握的
  11. 中断 http请求 正在加载 取消http请求
  12. 高斯滤波 c++实现
  13. Flutter 实现一款简单的音乐播放器
  14. [附源码]SSM计算机毕业设计逸尘房屋销售管理系统JAVA
  15. 扬帆起航——第一篇博客
  16. 矿物质饲料的全球与中国市场2022-2028年:技术、参与者、趋势、市场规模及占有率研究报告
  17. 以太坊(Ethereum) - 让浏览器支持区块链(MetaMask)
  18. 2019 下半年 Flutter 实现的性能优化 | 英雄榜
  19. python练习-统计出传入字符串参数(可能不只一个参数)的英文字母、空格、数字和其它字符的个数
  20. html的加重语气标签,史上最全的HTML代码

热门文章

  1. mysql集群session_Jetty9.2.2集群Session共享
  2. ldap导入mysql_openLDAP 部署(亲测可用)
  3. java poi 空_Java的poi技术遍历Excel时进行空Cell,空row,判断
  4. formate JAVA_JAVA String.format 方法使用
  5. 【springboot】【若依(ruoyi)】@RestController 接口跨域请求
  6. java.nio.file.FileSystemException: xxx: Too many open files
  7. java 中 Object XML 互转,最终选择Xstream
  8. Oracle dblink报错:ORA-01017、ORA-02063解决
  9. 找不到_我的圣诞礼物找不到了!
  10. spring事务(三)