残留网络

在介绍最大流算法之前先介绍一下什么是残留网络。残余网络的概念有点类似于集合中的补集概念。

下图是残余网络的样例。

上面的网络是原始网络。以下的网络是计算出的残留网络。残留网络的作用就是用来描写叙述这个网络中还剩下多少能够利用的流量。

流量网络

最大流算法比曾经介绍的算法都要复杂。

网络中的每一条边须要记录容量和当前流量。容量是固定值,是已知条件,而当前流量在计算过程中会一直发生变化。因此,须要建立一个专门的类,用于最大流算法。

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代码的更多相关文章

  1. 排序算法对比,步骤,改进,java代码实现

    前言 发现是时候总结一番算法,基本类型的增删改查的性能对比,集合的串并性能的特性,死记太傻了,所以还是写在代码里,NO BB,SHOW ME THE CODE! github地址:https://gi ...

  2. coding++:RateLimiter 限流算法之漏桶算法、令牌桶算法--简介

    RateLimiter是Guava的concurrent包下的一个用于限制访问频率的类 <dependency> <groupId>com.google.guava</g ...

  3. 常用限流算法与Guava RateLimiter源码解析

    在分布式系统中,应对高并发访问时,缓存.限流.降级是保护系统正常运行的常用方法.当请求量突发暴涨时,如果不加以限制访问,则可能导致整个系统崩溃,服务不可用.同时有一些业务场景,比如短信验证码,或者其它 ...

  4. 对一致性Hash算法,Java代码实现的深入研究

    一致性Hash算法 关于一致性Hash算法,在我之前的博文中已经有多次提到了,MemCache超详细解读一文中"一致性Hash算法"部分,对于为什么要使用一致性Hash算法.一致性 ...

  5. Ford-Fulkerson 最大流算法

    流网络(Flow Networks)指的是一个有向图 G = (V, E),其中每条边 (u, v) ∈ E 均有一非负容量 c(u, v) ≥ 0.如果 (u, v) ∉ E 则可以规定 c(u, ...

  6. 几种简单的负载均衡算法及其Java代码实现

    什么是负载均衡 负载均衡,英文名称为Load Balance,指由多台服务器以对称的方式组成一个服务器集合,每台服务器都具有等价的地位,都可以单独对外提供服务而无须其他服务器的辅助.通过某种负载分担技 ...

  7. 一致性哈希算法学习及JAVA代码实现分析

    1,对于待存储的海量数据,如何将它们分配到各个机器中去?---数据分片与路由 当数据量很大时,通过改善单机硬件资源的纵向扩充方式来存储数据变得越来越不适用,而通过增加机器数目来获得水平横向扩展的方式则 ...

  8. 大话数据结构(十二)java程序——KMP算法及改进的KMP算法实现

    1.朴素的模式匹配算法 朴素的模式匹配算法:就是对主串的每个字符作为子串开头,与要连接的字符串进行匹配.对主串做大循环,每个字符开头做T的长度的小循环,直到成功匹配或全部遍历完成为止. 又称BF算法 ...

  9. 常见的排序算法之Java代码解释

    一 简要介绍 一般排序均值的是将一个已经无序的序列数据重新排列成有序的 常见的排序分为: 1 插入类排序 主要就是对于一个已经有序的序列中,插入一个新的记录.它包括:直接插入排序,折半插入排序和希尔排 ...

随机推荐

  1. JavaScript 获取当月天数

    getDate() 方法可返回月份的某一天.取值范围是1~31 如果是0的话,就返回最后一天.这样就能取得当月的天数了 比如获取16年2月份的天数 var day = new Date(2016,2, ...

  2. 刚接触js不久,自己写的banner幻灯片效果。

    对于我这种菜鸟来讲,刚接触项目.叫我用插件,其实我说插件太臃肿不想用,倒不如说我是看不懂那些插件...- -(更愿意自己写点看得懂的代码,顺便也是个学习的过程) 所以自己花了些时间,自己来写了个dem ...

  3. Spring MVC 获取前端参数的注解

    在与前端交互的开发过程中,出现过几次无法取到参数的情况,费了些时间去排查问题,下面就简单总结一下. 注解详解 我们所要获取的前端传递参数大概可以分为以下四类: requet uri 部分的注解:@Pa ...

  4. js 中的流程控制-条件语句

    条件语句: if(exp)执行一句代码 <script> var x = 1 ; if(x == 1 ) //当if判断语句结果是true 或者 false 当判断结果等于true的时候, ...

  5. MySql数据库1【概念】

    [mysql] mysql是目前最主流的跨平台.开放源代码的关系型数据库,由瑞曲的mysql ab公司开发,已经被SUN公司收购,标识是一只名为sakila的海豚,代表mysql的速度.能力.精确优秀 ...

  6. Python爬虫第一步

    这只是记录一下自己学习爬虫的过程,可能少了些章法.我使用过的是Python3.x版本,IDE为Pycharm. 这里贴出代码集合,这一份代码也是以防自己以后忘记了什么,方便查阅. import req ...

  7. wndows常用命令

    1. 远程桌面 mstsc (Microsoft terminal services client)

  8. SQL语句の集锦

    6.删除数据后根据主键从备份表中恢复 insert  sameTable_1 (name,dz) select name,dz from sameTable_1_bak where not exist ...

  9. 大神眼中的React Native--备用

    当我第一次尝试ReactNative的时候,我觉得这只是网页开发者涉足原生移动应用领域的歪门邪道. 我认为一个js开发者可以使用javascript来构建iPhone应用确实是一件很酷的事情,但是我很 ...

  10. 转:[译]Autoprefixer:一个以最好的方式处理浏览器前缀的后处理程序

    原文来自于:http://www.cnblogs.com/aNd1coder/archive/2013/08/12/3252690.html Autoprefixer解析CSS文件并且添加浏览器前缀到 ...