该算法的原理来自线性规划,笔者还有没搞懂的地方,这里只谈实现。后面会给出完整的C++代码。
前提假设与问题点总结
事先有所了解的看官可以略过此小节。
如果一个节点是某些链路(或称有向边)的起点且不是任何链路的终点,则该节点为源节点(source);如果一个节点是某些链路的终点且不是任何链路的起点,则该节点为宿节点(sink).
每条链路都可以有一定的流量(flow),其方向必须与链路方向相同;一条链路上的流量允许的最大值称为该链路的容量(capacity)。
根据当前的流量情况,链路可分为三类:
满的(full), 流量已达到最大值,即等于容量
空的(empty), 流量为0
部分满的(partial), 流量大于0但小于容量
最大流问题:对于一个存在源、宿节点的网络,选取其中一个源节点s和一个宿节点t,要求除了这两点外,其他节点上出、入的流量相等。安排各链路的流量,使s的流出、t的流入(显然,两者必相等)达到最大值。
最小费用最大流问题:假设每一单位的流量经过一条链路时都会产生一定的费用(cost), 已知各条链路的费用,给出解决方案,在达到上述最大流的同时,总费用最小。
这里约定流量、费用都是整数值。
解决方法概述
主要分以下步骤:
1. 构造一条虚拟的从s到t的链路,它的容量足够大,大于原本从s流出的所有链路的容量之和,也大于流入t的所有链路的容量之和;它的费用特别高,大于其他所有链路的费用的总和。使其他链路的流量都为0,虚拟链路流量等于其容量。
此时若在原有的链路上发现任意一条从s到t的路径、并将虚拟链路上的一部分流量导入到该条路径上,总费用必然减小。如此最大流和最小费用的问题就统一起来了:为了让费用达到最小,必定要尽量避开那条假设的链路,使更多的流量从原先的链路上经过。
以下图作为例子,cap和cost分别代表容量和费用,s = 0, t = 5:
![23aa6bb2ba36175621420f0ce0f98536.png](https://i-blog.csdnimg.cn/blog_migrate/98fd50dc2c5363f779c96b9da46af845.png)
s和t之间构造一个假设的链路,其容量和费用这里设为7和16,如下图所示:
![4c1fa0aef1ea3bbf7ab60dee6e7444d8.png](https://i-blog.csdnimg.cn/blog_migrate/1e45861ff3e7c95d4abddd75e3b732a4.png)
初始阶段,只有虚拟链路是满的,流量为7,等于容量;其他链路流量均为0:
![5d2a994b0eee6cb9e52826465dcd69b2.png](https://i-blog.csdnimg.cn/blog_migrate/8c5cee6e5d4d4227b1cf8eea24b6706c.png)
2. 构造一个以t节点为根的生成树。且该树必须包含虚拟链路。
比如对于刚才的例子构造生成树如下(具体的构造步骤等具体到代码时再谈,这里可以不用关心)