▶ 书中第六章部分程序,包括在加上自己补充的代码,网络最大流 Ford - Fulkerson 算法,以及用到的流量边类和剩余流量网络类

● 网络最大流 Ford - Fulkerson 算法

 package package01;

 import edu.princeton.cs.algs4.StdOut;
import edu.princeton.cs.algs4.FlowEdge;
import edu.princeton.cs.algs4.FlowNetwork;
import edu.princeton.cs.algs4.Queue; public class class01
{
private static final double FLOATING_POINT_EPSILON = 1E-11; private final int V; // 顶点数
private boolean[] marked; // 已搜索顶点,marked[v] = true 表示从起点 s 到顶点 v 存在一条具有剩余流量的路径
private FlowEdge[] edgeTo; // s -> v 路径上的最后一条边
private double value; // 当前最大流量 public class01(FlowNetwork G, int s, int t)
{
V = G.V();
if (s == t || !isFeasible(G, s, t))
throw new IllegalArgumentException("\n<constructor> Source == Sink || !isFeasible(G, s, t).\n");
for (value = excess(G, t); hasAugmentingPath(G, s, t);) // 初始流量为顶点 t 净流量,只要还存在具有剩余容量的路径就要扩容
{
double bottle = Double.POSITIVE_INFINITY; // 沿着找到的路径走一遍,最小剩余容量作为扩容量
for (int v = t; v != s; v = edgeTo[v].other(v))
bottle = Math.min(bottle, edgeTo[v].residualCapacityTo(v));
for (int v = t; v != s; v = edgeTo[v].other(v)) // 扩容
edgeTo[v].addResidualFlowTo(v, bottle);
value += bottle; // 总流量也要增加
}
} public double value()
{
return value;
} public boolean inCut(int v) // 顶点 v 是否在 s-切分中
{
return marked[v];
} private boolean hasAugmentingPath(FlowNetwork G, int s, int t) // 判断是否存在从 s 到 t 的剩余容量路径
{
edgeTo = new FlowEdge[G.V()];
marked = new boolean[G.V()];
Queue<Integer> queue = new Queue<Integer>(); // 广度优先搜索,保持所有搜索过的路径都有剩余容量
for (queue.enqueue(s), marked[s] = true; !queue.isEmpty() && !marked[t];)
{
int v = queue.dequeue();
for (FlowEdge e : G.adj(v))
{
int w = e.other(v);
if (e.residualCapacityTo(w) > 0) // 如果取出的边关于终点 w 有剩余流量,则将其入队
{
if (!marked[w])
{
edgeTo[w] = e;
marked[w] = true;
queue.enqueue(w);
}
}
}
}
return marked[t]; // 如果搜索到过 t,说明存在一条具有剩余容量的路径
} private double excess(FlowNetwork G, int v) // 计算顶点 v 的净流量
{
double excess = 0.0;
for (FlowEdge e : G.adj(v)) // 入边增加,出边减少
excess += (v == e.to() ? e.flow() : -e.flow());
return excess;
} private boolean isFeasible(FlowNetwork G, int s, int t) // 节点流量异常检查
{
for (int v = 0; v < G.V(); v++)
{
for (FlowEdge e : G.adj(v))
{
if (e.flow() < -FLOATING_POINT_EPSILON || e.flow() > e.capacity() + FLOATING_POINT_EPSILON) // 某条边的流量异常
{
System.err.println("Edge does not satisfy capacity constraints: " + e);
return false;
}
}
}
if (Math.abs(value + excess(G, s)) > FLOATING_POINT_EPSILON)// 当前起点净流量(<0)加上图流量非零,异常
{
System.err.println("Excess at source = " + excess(G, s) + "Max flow = " + value);
return false;
}
if (Math.abs(value - excess(G, t)) > FLOATING_POINT_EPSILON)// 当前终点净流量(>0)减去图流量非零,异常
{
System.err.println("Excess at sink = " + excess(G, t) + "Max flow = " + value);
return false;
}
for (int v = 0; v < G.V(); v++) // 其他节点净流量应该为零
{
if (v == s || v == t)
continue;
if (Math.abs(excess(G, v)) > FLOATING_POINT_EPSILON)
{
System.err.println("Net flow out of " + v + " doesn't equal zero");
return false;
}
}
return true;
} public static void main(String[] args)
{
int V = Integer.parseInt(args[0]), E = Integer.parseInt(args[1]), s = 0, t = V - 1;
FlowNetwork G = new FlowNetwork(V, E);
StdOut.println(G);
class01 maxflow = new class01(G, s, t);
StdOut.println("Max flow from " + s + " to " + t);
for (int v = 0; v < G.V(); v++) // 打印所有具有流量的边
{
for (FlowEdge e : G.adj(v))
{
if ((v == e.from()) && e.flow() > 0)
StdOut.println(" " + e);
}
}
StdOut.print("Min cut: "); // 输出最小切分
for (int v = 0; v < G.V(); v++)
if (maxflow.inCut(v)) StdOut.print(v + " ");
StdOut.println("\nMax flow value = " + maxflow.value());
}
}

● 流量边类

 package package01;

 public class class01
{
private static final double FLOATING_POINT_EPSILON = 1E-10; private final int v; // 起点
private final int w; // 终点
private final double capacity; // 容量
private double flow; // 流量 public class01(int inputV, int inputW, double inputCapacity) // 三种构造函数
{
if (inputV < 0 || inputW < 0 || inputCapacity<0)
throw new IllegalArgumentException("\n<constructor> inputV < 0 || inputW < 0 || inputCapacity < 0.\n");
v = inputV;
w = inputW;
capacity = inputCapacity;
flow = 0.0;
} public class01(int inputV, int inputW, double inputCapacity, double inputFlow)
{
if (inputV < 0 || inputW < 0 || inputCapacity<0 || inputFlow < 0.0 || inputFlow > inputCapacity)
throw new IllegalArgumentException("\n<constructor> inputV < 0 || inputW < 0 || inputCapacity < 0 || flow < 0.0 || flow > capacity.\n");
v = inputV;
w = inputW;
capacity = inputCapacity;
flow = inputFlow;
} public class01(class01 e)
{
v = e.v;
w = e.w;
capacity = e.capacity;
flow = e.flow;
} public int from()
{
return v;
} public int to()
{
return w;
} public double capacity()
{
return capacity;
} public double flow()
{
return flow;
} public int other(int vertex)
{
if (vertex == v)
return w;
else if (vertex == w)
return v;
throw new IllegalArgumentException("\n<other> invalid endpoint.\n");
} public double residualCapacityTo(int vertex) // 计算一条边关于某个顶点的流通能力
{
if (vertex == v) // 起点,返回边的现有流量
return flow;
else if (vertex == w) // 终点,返回边的剩余容量
return capacity - flow;
throw new IllegalArgumentException("\n<residualCapacityTo> invalid endpoint.\n");
} public void addResidualFlowTo(int vertex, double delta) // 改变边的流量
{
if (delta < 0.0)
throw new IllegalArgumentException("\n<addResidualFlowTo> delta < 0.0.\n");
if (vertex == v) // 起点,边流量减少
flow -= delta;
else if (vertex == w) // 终点,边流量增加
flow += delta;
else
throw new IllegalArgumentException("\n<addResidualFlowTo> invalid endpoint.\n");
if (Math.abs(flow) <= FLOATING_POINT_EPSILON) // 流量归零
flow = 0;
if (Math.abs(flow - capacity) <= FLOATING_POINT_EPSILON) // 流量达到容量
flow = capacity;
if (flow < 0.0) // 流量异常
throw new IllegalArgumentException("\n<addResidualFlowTo> flow <0.\n");
if (flow > capacity)
throw new IllegalArgumentException("\n<addResidualFlowTo> flow > capacity.\n");
} public String toString()
{
return v + "->" + w + " " + flow + "/" + capacity;
} public static void main(String[] args)
{
class01 e = new class01(12, 23, 4.56);
StdOut.println(e);
}
}

● 剩余流量网络类

 package package01;

 import edu.princeton.cs.algs4.In;
import edu.princeton.cs.algs4.StdOut;
import edu.princeton.cs.algs4.StdRandom;
import edu.princeton.cs.algs4.FlowEdge;
import edu.princeton.cs.algs4.Bag; public class class01
{
private static final String NEWLINE = System.getProperty("line.separator"); private final int V;
private int E;
private Bag<FlowEdge>[] adj; public class01(int inputV)
{
if (V < 0)
throw new IllegalArgumentException("\n<constructor> inputV < 0.\n");
V = inputV;
E = 0;
adj = (Bag<FlowEdge>[]) new Bag[V];
for (int v = 0; v < V; v++)
adj[v] = new Bag<FlowEdge>();
} public class01(int inputV, int inputE)
{
this(inputV);
if (E < 0)
throw new IllegalArgumentException("\n<constructor> inputE < 0.\n");
for (int i = 0; i < E; i++)
addEdge(new FlowEdge(StdRandom.uniform(V), StdRandom.uniform(V), StdRandom.uniform(100)));
} public class01(In in)
{
this(in.readInt());
E = in.readInt();
for (int i = 0; i < E; i++)
addEdge(new FlowEdge(in.readInt(), in.readInt(), in.readDouble()));
} public int V()
{
return V;
} public int E()
{
return E;
} public void addEdge(FlowEdge e) // 添加一条边
{
adj[e.from()].add(e);
adj[e.to()].add(e);
E++;
} public Iterable<FlowEdge> adj(int v)// 一个顶点上出边的迭代器,就是该顶点的单链表
{
return adj[v];
} public Iterable<FlowEdge> edges() // 所有边的迭代器,和搜集所有顶点处的出边
{
Bag<FlowEdge> list = new Bag<FlowEdge>();
for (int v = 0; v < V; v++)
{
for (FlowEdge e : adj(v))
{
if (e.to() != v)
list.add(e);
}
}
return list;
} public String toString()
{
StringBuilder s = new StringBuilder();
s.append(V + " " + E + NEWLINE);
for (int v = 0; v < V; v++)
{
s.append(v + ": ");
for (FlowEdge e : adj[v])
if (e.to() != v) s.append(e + " ");
s.append(NEWLINE);
}
return s.toString();
} public static void main(String[] args)
{
In in = new In(args[0]);
class01 G = new class01(in);
StdOut.println(G);
}
}

《算法》第六章部分程序 part 5的更多相关文章

  1. 《算法》第六章部分程序 part 7

    ▶ 书中第六章部分程序,加上自己补充的代码,包括全局最小切分 Stoer-Wagner 算法,最小权值二分图匹配 ● 全局最小切分 Stoer-Wagner 算法 package package01; ...

  2. 《算法》第六章部分程序 part 6

    ▶ 书中第六章部分程序,包括在加上自己补充的代码,包括二分图最大匹配(最小顶点覆盖)的交替路径算法和 HopcroftKarp 算法 ● 二分图最大匹配(最小顶点覆盖)的交替路径算法 package ...

  3. 《算法》第六章部分程序 part 8

    ▶ 书中第六章部分程序,加上自己补充的代码,包括单纯形法求解线性规划问题 ● 单纯形法求解线性规划问题 // 表上作业法,I 为单位阵,y 为对偶变量,z 为目标函数值 // n m 1 // ┌── ...

  4. 《算法》第六章部分程序 part 4

    ▶ 书中第六章部分程序,包括在加上自己补充的代码,利用后缀树查找最长重复子串.查找最大重复子串并输出其上下文(Key word in context,KWIC).求两字符串的最长公共子串 ● 利用后缀 ...

  5. 《算法》第六章部分程序 part 3

    ▶ 书中第六章部分程序,包括在加上自己补充的代码,后缀树的两种实现 ● 后缀树实现一 package package01; import java.util.Arrays; import edu.pr ...

  6. 《算法》第六章部分程序 part 2

    ▶ 书中第六章部分程序,包括在加上自己补充的代码,B-树 ● B-树 package package01; import edu.princeton.cs.algs4.StdOut; public c ...

  7. 《算法》第六章部分程序 part 1

    ▶ 书中第六章部分程序,包括在加上自己补充的代码,粒子碰撞系统及用到的粒子类 ● 粒子系统 package package01; import java.awt.Color; import edu.p ...

  8. 《算法》第一章部分程序 part 1

    ▶ 书中第一章部分程序,加上自己补充的代码,包括若干种二分搜索,寻找图上连通分量数的两种算法 ● 代码,二分搜索 package package01; import java.util.Arrays; ...

  9. 《算法》第二章部分程序 part 5

    ▶ 书中第二章部分程序,加上自己补充的代码,包括利用优先队列进行多路归并和堆排序 ● 利用优先队列进行多路归并 package package01; import edu.princeton.cs.a ...

随机推荐

  1. Mysql 性能优化7【重要】sql语句的优化 慢查询

    慢查询时间设置 慢查询日志分析工具 另一个慢查询日志分析工具 如何对sql进行特定的优化

  2. 使用JavaScript完成文字向上间歇滚动

    使用JavaScript完成文字的间歇滚动 const init = (initData) => { const area = initData.area; // 设置单行滚动的高度: cons ...

  3. Comparator 排序 ArrayList 实操练习

    package ltb6w; import java.util.Scanner;import java.util.ArrayList;import java.util.Comparator;impor ...

  4. 我的ehcache笔记

    我的EhcacheUtils类: package com.shinho.bi.utils; import org.ehcache.CacheManager; import org.ehcache.co ...

  5. neo4j---删除关系和节点

    本文转载自:https://blog.csdn.net/chenjf0221/article/details/70238695 删除节点和节点关系 MATCH (a:key)-[r:KEY_WORD] ...

  6. Bitmap BitmapData

    var sp:Sprite=new Sprite(); sp.graphics.beginFill(0xffccdd); sp.graphics.drawRect(0,0,100,100); sp.g ...

  7. uoj#187. 【UR #13】Ernd

    http://uoj.ac/problem/187 每个点只能从时间,b+a,b-a三维都不大于它的点转移过来,将点按时间分成尽量少的一些段,每段内三维同时非严格单调,每段内的点可能因为连续选一段而产 ...

  8. .NET数据请求序列化

    这是一个.ner框架中经常用到的数据映射类,此类主要承接业务应用做数据的增删查改操作.通过序列化将查询数据映射为需要的类. 由于经常会用到,这里收藏一下. data用作SQL数据库链接操作: Repo ...

  9. spring4.0之八:Groovy DSL

    4.0的一个重要特征就是完全支持Groovy,Groovy是Spring主导的一门基于JVM的脚本语言(动态语言).在spring 2.x,脚本语言通过 Java scripting engine在S ...

  10. jQuery版本问题,及事件源

    jQuery版本的分界线是2.0 2.0之前很多方法支持ie低版本,2.0之后就不支持了 工具:index() 指定元素的索引  (有参数) 不传参的情况下,父级元素下同级元素的排名,传参:指定元素的 ...