残留网络

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

下图是残余网络的样例。

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

流量网络

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

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

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. 控制寄存器 CR*

    控制寄存器(CR0-CR3)用于控制和确定处理器的操作模式以及当前执行任务的特性,如图4-3所示.CR0中含有控制处理器操作模式和状态的系统控制标志:CR1保留不用:CR2含有导致页错误的线性地址:C ...

  2. Devexpress Barmanager设置

    一,在bar的属性中有optionbar,可以做一些设置. 其中比较有用的是:1,去掉最右边的箭头:allowquickcustomization 改为false 2,去掉最左边的竖线:drawdra ...

  3. PHP图片操作

    <?php $filename="http://pic.nipic.com/2007-12-06/2007126102233577_2.jpg";//图片地址//获取图片信息 ...

  4. php——composer 1、安装使用

    Composer 是PHP中用来管理依赖(dependency)关系的工具.你可以在自己的项目中声明所依赖的外部工具库(libraries),Composer会帮你安装这些依赖的库文件. 系统要求 运 ...

  5. php把文件上传到远程服务器上例子

    在这里我们利用curl实现把本地服务器的文件通过curl发送请求给远程服务器的php文件接受就实现了上传,还一个是利用ftp来上传方法也是php中的curl操作ftp服务器进行上传. 我这里写的是用c ...

  6. Why is 0[0] syntactically valid in javascript?

    Why is 0[0] syntactically valid in javascript? 原文链接 偶然在一篇帖子中看到了这个问题,所以打算记录一下. var a = 0[0]; console. ...

  7. Python中几种数据结构的整理,列表、字典、元组、集合

    列表:shoplist = ['apple', 'mango', 'carrot', 'banana']字典:di = {'a':123,'b':'something'}集合:jihe = {'app ...

  8. 转:.NET中使用Redis (一)

    原文来自于:http://blog.jobbole.com/83821/ 原文出处: 寒江独钓   欢迎分享原创到伯乐头条 Redis是一个用的比较广泛的Key/Value的内存数据库,新浪微博.Gi ...

  9. K Smallest Sums

    uva11997:http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_prob ...

  10. Android 中使用MediaRecorder进行录像详解(视频录制)

    在这里给出自己的一个测试DEMO,里面注释很详细.简单的视频录制功能. package com.video; import java.io.IOException; import android.ap ...