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

甲军的运输路线

  假设甲、乙两军正在交战,图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位的”

网络流(3)——找到最小st-剪切的更多相关文章

  1. Cogs 728. [网络流24题] 最小路径覆盖问题

    [网络流24题] 最小路径覆盖问题 ★★☆ 输入文件:path3.in 输出文件:path3.out 评测插件 时间限制:1 s 内存限制:128 MB 算法实现题8-3 最小路径覆盖问题(习题8-1 ...

  2. cogs 728. [网络流24题] 最小路径覆盖问题 匈牙利算法

    728. [网络流24题] 最小路径覆盖问题 ★★★☆   输入文件:path3.in   输出文件:path3.out   评测插件时间限制:1 s   内存限制:128 MB 算法实现题8-3 最 ...

  3. 网络流 最大流—最小割 之SAP算法 详解

    首先引入几个新名词: 1.距离标号: 所谓距离标号 ,就是某个点到汇点的最少的弧的数量(即边权值为1时某个点到汇点的最短路径长度). 设点i的标号为level[i],那么如果将满足level[i]=l ...

  4. 十依据一个有用的算法来找到最小(最大)的k的数量-线性搜索算法

    例如:进入1.2.3,4,5,6.7.8此8数字,最小的4图的1,2,3,4. 思路1:最easy想到的方法:先对这个序列从小到大排序.然后输出前面的最小的k个数就可以.假设选择高速排序法来进行排序, ...

  5. 【BZOJ】2561: 最小生成树【网络流】【最小割】

    2561: 最小生成树 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 2685  Solved: 1253[Submit][Status][Discu ...

  6. 【洛谷】4304:[TJOI2013]攻击装置【最大点独立集】【二分图】2172: [国家集训队]部落战争【二分图/网络流】【最小路径覆盖】

    P4304 [TJOI2013]攻击装置 题目描述 给定一个01矩阵,其中你可以在0的位置放置攻击装置. 每一个攻击装置(x,y)都可以按照“日”字攻击其周围的8个位置(x-1,y-2),(x-2,y ...

  7. P2764 [网络流24题]最小路径覆盖问题[最大流]

    地址 这题有个转化,求最少的链覆盖→即求最少联通块. 设联通块个数$x$个,选的边数$y$,点数$n$个 那么有 $y=n-x$   即  $x=n-y$ 而n是不变的,目标就是在保证每个点入度.出度 ...

  8. P1361 小M的作物 【网络流】【最小割】

    题目描述 小M在MC里开辟了两块巨大的耕地A和B(你可以认为容量是无穷),现在,小P有n中作物的种子,每种作物的种子有1个(就是可以种一棵作物)(用1...n编号). 现在,第i种作物种植在A中种植可 ...

  9. 【uva 1349】Optimal Bus Route Design(图论--网络流 二分图的最小权完美匹配)

    题意:有一个N个点的有向带权图,要求找若干个有向圈,使得每个点恰好属于一个圈.请输出满足以上条件的最小权和. 解法:有向圈?也就是每个点有唯一的后继.这是一个可逆命题,同样地,只要每个点都有唯一的后继 ...

随机推荐

  1. vs code 运行 Django 怎么修改端口

    1.具体操作步骤如下 默认情况下,通过 python manage.py runserver 命令行模式默认打开是 8000 端口,如下图所示: 在浏览器预览效果如下: 为了防止端口冲突,我们一般会修 ...

  2. go语言设计模式之proxy

    代理模式,单元测试用例真的写得详细, 受教~ proxy.go package proxy import ( //"errors" "fmt" ) type U ...

  3. CookieJar转换成不同的数据格式

  4. UVA 503 Parallelepiped walk

    https://vjudge.net/problem/UVA-503 题目 给出一个长方体和长方体上两点的坐标,求两点的沿着长方体表面走的最小距离 题解 沿着表面走就是在展开图上面走,如果分类讨论就需 ...

  5. acwing 2 零一背包问题

    地址 https://www.acwing.com/problem/content/description/2/ 题目描述有 N 件物品和一个容量是 V 的背包.每件物品只能使用一次. 第 i 件物品 ...

  6. macOS 安装 Docker Desktop CE(转)

    现在基本上都使用docker进行部署项目,所以还是有必要学习下,关于docker的简介这里就不在描述,本文转载自https://yeasy.gitbooks.io/docker_practice/co ...

  7. jinja2模板用法

    我不是代码的生产者,我只是知识的搬运工 jinja2模板用法

  8. 移动端px自动转化为rem

    注:不转换的px用大写PX代替 lib-flexible 作用:让网页根据设备dpr和宽度,利用viewport和html根元素的font-size配合rem来适配不同尺寸的移动端设备 安装:cnpm ...

  9. 关于group by的用法 原理

    转载: https://blog.csdn.net/u014717572/article/details/80687042. 写在前面的话:用了好久group by,今天早上一觉醒来,突然感觉grou ...

  10. Codeforces Round #594 (Div. 1) D. Catowice City 图论

    D. Catowice City In the Catowice city next weekend the cat contest will be held. However, the jury m ...