残留网络

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

下图是残余网络的样例。

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

流量网络

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

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

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. 不使用ASP.NET服务器端控件(包括form表单不加runat="server")来触发.cs里的事件(方法),(适用于有代码洁癖者)。

    很多时候,我们使用服务器端控件写出的代码,会给我们生成一些很多我们看不懂的代码(初学者),但是有时候我们并不需要这些代码(业务需求不同),对于生成的一些代码感到多余.所以我就开始想,有没有一种可能:不 ...

  2. CentOS Device eth0 does not seem to be present 解决方案

    1. vi /etc/udev/rules.d/70-persistent-net.rules 记录eth1 的网卡地址 2.vi /etc/sysconfig/network-scrpits/ifc ...

  3. cos-26上传个人案例

    package cn.gdpe.upload; import java.io.File;import java.io.IOException;import java.util.Enumeration; ...

  4. [C#]获取最近在Windows上所使用的文件

    class RecentlyFileHelper { public static string GetShortcutTargetFile(string shortcutFilename) { var ...

  5. 实例:jQuery实现标签切换

    具体实现效果如图: 原理很简单,就是监听鼠标滑动和点击事件.在第一个标签切换的示例中,当鼠标滑过某个标签时,就把class转移到当前标签.这里用到的jQuery方法主要是each()确定当前是哪一个标 ...

  6. phpexcel 一些基本的设置 (表格的基本属性)

    网址是:http://www.thinkphp.cn/code/1893.html

  7. Java线程运行轨迹-代码追踪与定位

    今天在写程序时,想到一个问题,当我的程序出异常的时候,控制台输出信息中,明确指出了出现异常的位置,并详细列举了函数的调用层次关系,它是怎么做到的. 竟然想到了这个问题,就去查看了源代码,不过没点几下, ...

  8. Leetcode: Reverse Integer 正确的思路下-要考虑代码简化

    题目: Reverse digits of an integer. Example1: x = 123, return 321Example2: x = -123, return -321 Have ...

  9. gcc将多个静态库链接成一个静态库

    参考:https://sourceware.org/binutils/docs/binutils/ar-scripts.html#ar-scripts makefile如下: ARSCRIPT=scr ...

  10. ORACLE 日志 logminer 使用

    1. logminer安装 SQL> @$ORACLE_HOME/rdbms/admin/dbmslm.sql Package created. Grant succeeded. Synonym ...