▶ 书中第六章部分程序,包括在加上自己补充的代码,网络最大流 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. 17行代码解决微信小程序图片延迟加载

    js 页面 Page({ data: { realScrollTop: 0,//页面滚动距离 driveHeight //屏幕高度可初始化设置 }, scroll(e){ if(e.detail.sc ...

  2. setvlet基础知识

    Servlet简介 Servlet是sun公司提供的一门用于开发动态web资源的技术. Sun公司在其API中提供了一个servlet接口,用户若想用发一个动态web资源(即开发一个Java程序向浏览 ...

  3. 【java】之正则表达式摘要

    构造 匹配 字符 x 字符 x \\ 反斜线字符 \0n 带有八进制值 0 的字符 n (0 <= n <= 7) \0nn 带有八进制值 0 的字符 nn (0 <= n < ...

  4. 【java】之equals和==区别

      Java中数据类型可以分为两类 1.基本数据类型(byte,short,char,int,float,double,long,boolean) 2.复合数据类型(类,String等) Δ在基本数据 ...

  5. C++进阶--公有继承的二元性

    //########################################################################### /* * 公有继承的两元性 * * - 接口 ...

  6. R语言—统计结果输出至本地文件方法总结

    1.sink()在代码开始前加一行:sink(“output.txt”),就会自动把结果全部输出到工作文件夹下的output.txt文本文档.这时在R控制台的输出窗口中是看不到输出结果的.代码结束时用 ...

  7. Ajax传参讲解

    客户端和服务器 1.请求:request 2.响应:response 服务器响应事件:onreadystatechange() send() 用于向后台传递参数: Ajax的请求方式 get:    ...

  8. C语言强化——数组

    打印九九乘法表 #include<stdio.h> int main() { int num = 1; for (int i = 1;i <= 9;++i) { for (int j ...

  9. OpenStack镜像服务基本操作

    查询Glance服务状态 #glance-control all status [root@controller ~]# glance-control all status glance-api (p ...

  10. volley 之GsonRequest

    这是之前写的http://www.cnblogs.com/freexiaoyu/p/3955137.html 关于GsonReques的用户,这个在POST请求传参数的时候GsonRequest构造第 ...