《算法》第六章部分程序 part 5
▶ 书中第六章部分程序,包括在加上自己补充的代码,网络最大流 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的更多相关文章
- 《算法》第六章部分程序 part 7
▶ 书中第六章部分程序,加上自己补充的代码,包括全局最小切分 Stoer-Wagner 算法,最小权值二分图匹配 ● 全局最小切分 Stoer-Wagner 算法 package package01; ...
- 《算法》第六章部分程序 part 6
▶ 书中第六章部分程序,包括在加上自己补充的代码,包括二分图最大匹配(最小顶点覆盖)的交替路径算法和 HopcroftKarp 算法 ● 二分图最大匹配(最小顶点覆盖)的交替路径算法 package ...
- 《算法》第六章部分程序 part 8
▶ 书中第六章部分程序,加上自己补充的代码,包括单纯形法求解线性规划问题 ● 单纯形法求解线性规划问题 // 表上作业法,I 为单位阵,y 为对偶变量,z 为目标函数值 // n m 1 // ┌── ...
- 《算法》第六章部分程序 part 4
▶ 书中第六章部分程序,包括在加上自己补充的代码,利用后缀树查找最长重复子串.查找最大重复子串并输出其上下文(Key word in context,KWIC).求两字符串的最长公共子串 ● 利用后缀 ...
- 《算法》第六章部分程序 part 3
▶ 书中第六章部分程序,包括在加上自己补充的代码,后缀树的两种实现 ● 后缀树实现一 package package01; import java.util.Arrays; import edu.pr ...
- 《算法》第六章部分程序 part 2
▶ 书中第六章部分程序,包括在加上自己补充的代码,B-树 ● B-树 package package01; import edu.princeton.cs.algs4.StdOut; public c ...
- 《算法》第六章部分程序 part 1
▶ 书中第六章部分程序,包括在加上自己补充的代码,粒子碰撞系统及用到的粒子类 ● 粒子系统 package package01; import java.awt.Color; import edu.p ...
- 《算法》第一章部分程序 part 1
▶ 书中第一章部分程序,加上自己补充的代码,包括若干种二分搜索,寻找图上连通分量数的两种算法 ● 代码,二分搜索 package package01; import java.util.Arrays; ...
- 《算法》第二章部分程序 part 5
▶ 书中第二章部分程序,加上自己补充的代码,包括利用优先队列进行多路归并和堆排序 ● 利用优先队列进行多路归并 package package01; import edu.princeton.cs.a ...
随机推荐
- linux svn客户端通过 https访问windows VisualSVN Server Manager
1)需求: 已经在阿里云windwos系统 下面安装了VisualSVN Server Manager 做为svn服务器: 现在要在腾讯云源码安装新版本客户端 2)开始源码编译安装TortoiseSV ...
- C/C++基础----标准库几个工具库tuple,bitset,正则表达式,随机数,IO库
tuple tuple可以有任意多个成员 默认初始化,值初始化 构造函数是explicit,必须直接初始化 make_tuple(v1,v2,-,vn) get<i> (t) 返回第i个数 ...
- C++之二阶构造模式
前言:C++中经常会因为调用系统资源失败导致出现BUG,所以在类调用构造函数需要分配系统资源时会出现BUG,从而导致类对象虽然被创建,但是只是个半成品,为了避免这种情况需要使用二阶构造模式 二阶构造模 ...
- linux安装tomcat9
0:环境准备 : 安装tomcat需要先配置jdk,所以没有配置jdk同学,先移步Linux安装JDK 或者使用比较便捷的方法,就是apt-get或者yum安装openJDK,这样做的话,会帮 ...
- keras LSTM学习实例
1. 购物时间预测 http://www.cnblogs.com/arkenstone/p/5794063.html https://github.com/CasiaFan/time_seires_p ...
- docker容器内外相互拷贝数据
从宿主机上拷贝文件到容器内 注意:一下红色字体为宿主机文件 docker cp 文件 容器名:目录 # docker cp httpd-2.4.34.tar.gz node4:/opt/ 从宿主机上拷 ...
- Jmeter(二)Jmeter目录介绍
看过许多有关Jmeter的博客,算得上的收获颇丰:不过最牛逼的博客还是“官方文档”,官方文档是ApacheJmeter自己对自己产品的说明,论起对自己产品的理解程度,那肯定是自己嘛...因此推荐大家从 ...
- [UE4]蓝图:重写父类时调用父类方法
右键重写的方法选择“Add call to parent function” 一定要善用这个功能,实现原有父类功能的同时实现子类特别的功能.
- VMware虚拟机上配置nginx后,本机无法访问问题(转载)
转自:http://www.server110.com/nginx/201407/10794.html 把nginx装在CentOS上,用本机访问虚拟机的时候却出现了不能访问的问题,查了资料以后,原来 ...
- java 根据日期获取星期
private String getWeek(String date) { String[] arr=date.split("-"); Calendar calendar = Ca ...