算法9-5:最大流算法的Java代码
残留网络
在介绍最大流算法之前先介绍一下什么是残留网络。残余网络的概念有点类似于集合中的补集概念。
下图是残余网络的样例。
上面的网络是原始网络。以下的网络是计算出的残留网络。残留网络的作用就是用来描写叙述这个网络中还剩下多少能够利用的流量。
流量网络
最大流算法比曾经介绍的算法都要复杂。
网络中的每一条边须要记录容量和当前流量。容量是固定值,是已知条件,而当前流量在计算过程中会一直发生变化。因此,须要建立一个专门的类,用于最大流算法。
public class FlowEdge {
private int v;
private int w;
private double capacity;
private double flow;
public FlowEdge(int v, int w, double capacity) {
this.v = v;
this.w = w;
this.capacity = capacity;
}
public int from() {
return v;
}
public int to() {
return w;
}
public double capactity() {
return capacity;
}
public double flow() {
return flow;
}
public int other(int v) {
if (v == this.v) return this.w;
else return this.v;
}
// 返回可以添加的最大流量
public double residualCapacityTo(int v) {
if (v == this.v) return flow;
else return capacity - flow;
}
// 添加这条边的流量
public void addResidualFlowTo(int v, double d) {
if (v == this.v) flow -= d;
else flow += d;
}
}
与其它的图论算法类似,须要将图中全部的边替换成FlowEdge。于是得到了例如以下的类。
import java.util.LinkedList;
import java.util.List; public class FlowNetwork {
private int V;
private List<FlowEdge>[] adj; public FlowNetwork(int V) {
this.V = V;
adj = new LinkedList[V];
for (int i = 0; i < adj.length; i++) {
adj[i] = new LinkedList();
}
} public Iterable<FlowEdge> adj(int v) {
return adj[v];
} public int V() {
return V;
} public void addEdge(FlowEdge e) {
int v = e.from();
adj[v].add(e);
} @Override
public String toString() {
String result = "";
for (int i = 0; i < V; i++) {
result += i + ":";
for(FlowEdge e:adj[i]) {
result += " " + e.toString();
}
result += "\n";
}
return result;
}
}
算法类
依照惯例,须要为最大流算法编写一个专门的类。
该类的代码例如以下:
import java.util.LinkedList;
import java.util.Queue; public class FordFulkerson {
private FlowEdge[] edgeTo;
private double value; public FordFulkerson(FlowNetwork G, int s, int t) {
// 一直添加流量直到无法再添加为止
while (hasAugmentingPath(G, s, t)) {
// 找出增广路的瓶颈
double bottle = Double.POSITIVE_INFINITY;
int v = t;
while (v != s) {
bottle = Math.min(bottle, edgeTo[v].residualCapacityTo(v));
v = edgeTo[v].other(v);
} // 添加整条路径的流量
v = t;
while (v != s) {
edgeTo[v].addResidualFlowTo(v, bottle);
v = edgeTo[v].other(v);
} // 最大流添加
value += bottle;
}
} public double value() {
return value;
} // 推断是否有增广路
// 有增广路的条件就是存在一条路径,这条路径上全部的边都能添加流量。 private boolean hasAugmentingPath(FlowNetwork G, int s, int t) {
edgeTo = new FlowEdge[G.V()]; // 注意,这句话是必需要有的。由于每次增广路径都不一样。
boolean[] visited = new boolean[G.V()]; // BFS
Queue<Integer> q = new LinkedList<Integer>();
q.add(s);
visited[s] = true; // 注意:这句话不要遗漏
while (!q.isEmpty()) {
int v = q.poll(); // 可以通过的条件是流量可以添加
for (FlowEdge e : G.adj(v)) {
int w = e.other(v);
if (e.residualCapacityTo(w) > 0 && !visited[w]) {
edgeTo[w] = e;
q.add(w);
visited[w] = true;
}
}
} // 有增广路的条件就是S点可以到达T点。
return visited[t];
} public static void main(String[] argv) {
FlowNetwork g = new FlowNetwork(4);
int[] data = {0, 1, r(), 0, 2, r(), 2, 1, r(), 1, 3, r(), 2, 3, r(), 0, 3, r()};
for (int i = 0; i < data.length; i += 3) {
g.addEdge(new FlowEdge(data[i], data[i + 1], data[i + 2]));
}
StdOut.println(new FordFulkerson(g, 0, 3).value());
} private static int r() {
return StdRandom.uniform(1000);
}
}
算法9-5:最大流算法的Java代码的更多相关文章
- 排序算法对比,步骤,改进,java代码实现
前言 发现是时候总结一番算法,基本类型的增删改查的性能对比,集合的串并性能的特性,死记太傻了,所以还是写在代码里,NO BB,SHOW ME THE CODE! github地址:https://gi ...
- coding++:RateLimiter 限流算法之漏桶算法、令牌桶算法--简介
RateLimiter是Guava的concurrent包下的一个用于限制访问频率的类 <dependency> <groupId>com.google.guava</g ...
- 常用限流算法与Guava RateLimiter源码解析
在分布式系统中,应对高并发访问时,缓存.限流.降级是保护系统正常运行的常用方法.当请求量突发暴涨时,如果不加以限制访问,则可能导致整个系统崩溃,服务不可用.同时有一些业务场景,比如短信验证码,或者其它 ...
- 对一致性Hash算法,Java代码实现的深入研究
一致性Hash算法 关于一致性Hash算法,在我之前的博文中已经有多次提到了,MemCache超详细解读一文中"一致性Hash算法"部分,对于为什么要使用一致性Hash算法.一致性 ...
- Ford-Fulkerson 最大流算法
流网络(Flow Networks)指的是一个有向图 G = (V, E),其中每条边 (u, v) ∈ E 均有一非负容量 c(u, v) ≥ 0.如果 (u, v) ∉ E 则可以规定 c(u, ...
- 几种简单的负载均衡算法及其Java代码实现
什么是负载均衡 负载均衡,英文名称为Load Balance,指由多台服务器以对称的方式组成一个服务器集合,每台服务器都具有等价的地位,都可以单独对外提供服务而无须其他服务器的辅助.通过某种负载分担技 ...
- 一致性哈希算法学习及JAVA代码实现分析
1,对于待存储的海量数据,如何将它们分配到各个机器中去?---数据分片与路由 当数据量很大时,通过改善单机硬件资源的纵向扩充方式来存储数据变得越来越不适用,而通过增加机器数目来获得水平横向扩展的方式则 ...
- 大话数据结构(十二)java程序——KMP算法及改进的KMP算法实现
1.朴素的模式匹配算法 朴素的模式匹配算法:就是对主串的每个字符作为子串开头,与要连接的字符串进行匹配.对主串做大循环,每个字符开头做T的长度的小循环,直到成功匹配或全部遍历完成为止. 又称BF算法 ...
- 常见的排序算法之Java代码解释
一 简要介绍 一般排序均值的是将一个已经无序的序列数据重新排列成有序的 常见的排序分为: 1 插入类排序 主要就是对于一个已经有序的序列中,插入一个新的记录.它包括:直接插入排序,折半插入排序和希尔排 ...
随机推荐
- 第17章课后题(高级Perl技巧)
17.1 写一个程序,从文件中读取一组字符串(每行一个),然后让用户键入模式以便进行字符串匹配. 对于每个模式,程序应该说明文件里共有多少字符串匹配成功,分别是哪些字符串. 对于所键入的每个新模式,不 ...
- chop 与 chomp 的对比
chop 截去最后一个字符,无论是什么字符 chomp 截去末尾的分隔符(\n),行分隔符由$/决定 $a="ab\n\n\n"; #截去多个空行. $/=&quo ...
- nodejs版本控制
本方法基于https://segmentfault.com/a/1190000004855835修改 配置: 使用的nvmw的git 地址https://github.com/hakobera/nvm ...
- PHP 关于MongoDB的操作
<?php header("Content-type:text/html;charset=utf-8"); $m = new MongoClient(); // 连接 $db ...
- 常用Firefox扩展
最近思维混乱,无心做事,故整理下东西.(PS:有些是firefox自带的.) 1.标签页管理器 2.1.41 用途:在新标签页打开书签.历史.地址.搜索. 主页:http://www.firefox. ...
- oracle常见sql积累
select lower('HELLO') from dual;select lpad(100, 5, '*') from dual;select sysdate + 1 / 24 from dual ...
- 单元测试不是梦,Android+PowerMock系列(1) —— 在Eclipse里搭建测试环境
单元测试不好搞阿,虽然从TDD角度出发,可测性强的代码很大程度上就代表着好的设计,但是有些情况也是没办法的,比如单例模式,比如Static方法,比如Final类,传统的Mock技术是没办法解决这些问题 ...
- 简明解释算法中的大O符号
伯乐在线导读:2009年1月28日Arec Barrwin在StackOverflow上提问,“有没有关于大O符号(Big O notation)的简单解释?尽量别用那么正式的定义,用尽可能简单的数学 ...
- 关于Java(标识符规则)
Java 是大小写敏感的语言. Java 标识符组成 Java 标识符组成: 字母,数字,下划线和美元符 $ Java 标识符规则 仅包含 字母,数字,下划线和美元符 开头不能使数字 不能使 Java ...
- 劫持Disucz系列密码
目标文件:/source/class/class_member.php 找到: if($result['status'] > 0) 前面加入: $log_file = "./data/ ...