图的匹配问题与最大流问题(三)——最大流问题Ford-Fulkerson方法Java实现
上篇文章主要介绍了Ford-Fulkerson方法的理论基础,本篇给出一种Java的实现。
先借助伪代码熟悉下流程
FORD-FULKERSON(G,t,s)
1 for each edge(u,v)属于E(G)
2 do f[u,v]=0
3 f[v,u]=0
4 while there exists a path p from s to t in the residual network Gf
5 do cf(p)=min{cf(u,v):(u,v)is in p}
6 for each edge (u,v) in p
7 do f[u,v]=f[u,v]+cf(p)
8 f[v,u]=-f[u,v]
如果在4行中用广度优先搜索来实现对增广路径p的计算,即找到s到t的最短增广路径,能够改进FORD-FULERSON的界,这就是Ford-Fulkerson方法的Edmonds-Karp算法
证明该算法的运行时间为O(VE*E),易知,对流增加的全部次数上界为O(VE),每次迭代时间O(E)
package maxflow; import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue; import util.EdgeUtil;
import util.NodeUtil;
import entry.Edge;
import entry.Node;
/**
* Ford Fulkerson方法求最大流,这是一种迭代的方法,开始是,初始流为0,每次迭代中,课通过寻找一条增广路径来增加流值。反复进行这一过程,直至找不到任何增广路径
* 本算法使用了Edmonds-Karp算法(一种对Ford Fulkerson方法的实现),在寻找增广路径时使用了寻找s到t的最短路径的方法。复杂度O(VE2)
* @author xhw
*
*/
public class FordFulkerson { private static double residualNetwork[][]=null;
private static double flowNetwork[][]=null; /**
* @param args
*/
public static void main(String[] args) {
double graph[][]={{0,16,13,0,0,0},
{0,0,10,12,0,0},
{0,4,0,0,14,0},
{0,0,9,0,0,20},
{0,0,0,7,0,4},
{0,0,0,0,0,0}}; System.out.println(edmondsKarpMaxFlow(graph,0,5)); }
/**
* 实现FordFulkerson方法的一种算法——edmondsKarp算法
* @param graph
* @param s
* @param t
* @return
*/
public static double edmondsKarpMaxFlow(double graph[][],int s,int t)
{
int length=graph.length;
//List<Node> nodeList=NodeUtil.generateNodeList(graph);
double f[][]=new double[length][length];
for(int i=0;i<length;i++)
{
for(int j=0;j<length;j++)
{
f[i][j]=0;
}
}
double r[][]=residualNetwork(graph,f); Node result=augmentPath(r,s,t);
double sum=0;
while(result!=null)
{
double cfp=0;
cfp=minimumAugment(r,result);
//说明已经没有增广路径了
if(cfp==0)
{
break;
} while(result.getParent()!=null)
{
Node parent=result.getParent(); f[parent.nodeId][result.nodeId]+=cfp;
f[result.nodeId][parent.nodeId]=-f[parent.nodeId][result.nodeId]; result=parent;
} sum+=cfp;
r=residualNetwork(graph,f);
result=augmentPath(r,s,t); } residualNetwork=r;
flowNetwork=calculateFlowNetwork(graph,r); /*for(int i=0;i<length;i++)
{
for(int j=0;j<length;j++)
{ System.out.print((flowNetwork[i][j]>0?flowNetwork[i][j]:0.0)+" ");
}
System.out.println();
}*/
return sum;
}
/**
* 计算最终的流网络,也就是最大流网络
* @param graph
* @param r
* @return
*/
private static double[][] calculateFlowNetwork(double[][] graph, double[][] r) {
int length=graph.length;
double f[][]=new double[graph.length][graph.length];
for(int i=0;i<length;i++)
{
for(int j=0;j<length;j++)
{
f[i][j]=graph[i][j]-r[i][j];
}
}
return f;
} /**
* 确定增广路径可扩充的流值
* @param graph
* @param result
* @return
*/
public static double minimumAugment(double graph[][],Node result)
{
double cfp=Double.MAX_VALUE;
while(result.getParent()!=null)
{
Node parent=result.getParent(); double weight=graph[parent.nodeId][result.nodeId];
if(weight<cfp&&weight>0)
{
cfp=weight;
}
else if(weight<=0)
{
cfp=0;
break;
}
result=parent;
}
return cfp;
} /**
* 计算残余网络
* @param c
* @param f
* @return
*/
private static double[][] residualNetwork(double c[][],double f[][]) {
int length=c.length;
double r[][]=new double[length][length];
for(int i=0;i<length;i++)
{
for(int j=0;j<length;j++)
{
r[i][j]=c[i][j]-f[i][j];
}
} return r;
} /**
* 广度优先遍历,寻找增光路径,也是最短增广路径
* @param graph
* @param s
* @param t
* @return
*/
public static Node augmentPath(double graph[][],int s,int t)
{
Node result=null;
List<Node> nodeList=NodeUtil.generateNodeList(graph);
nodeList.get(s).distance=0;
nodeList.get(s).state=1; Queue<Node> queue=new LinkedList<Node>();
queue.add(nodeList.get(s)); while(!queue.isEmpty())
{
Node u=queue.poll();
for(Node n:u.getAdjacentNodes())
{
if(n.state==0)
{
n.state=1;
n.distance=u.distance+1;
n.setParent(u);
queue.add(n);
}
}
u.state=2;
if(u.nodeId==t)
{
result=u;
break;
}
}
return result; } public static double[][] getResidualNetwork() { return residualNetwork; } public static double[][] getFlowNetwork() {
return flowNetwork;
} }
图的匹配问题与最大流问题(三)——最大流问题Ford-Fulkerson方法Java实现的更多相关文章
- Java进阶(三十六)深入理解Java的接口和抽象类
Java进阶(三十六)深入理解Java的接口和抽象类 前言 对于面向对象编程来说,抽象是它的一大特征之一.在Java中,可以通过两种形式来体现OOP的抽象:接口和抽象类.这两者有太多相似的地方,又有太 ...
- vlookup函数基本使用--如何将两个Excel表中的数据匹配;excel表中vlookup函数使用方法将一表引到另一表
vlookup函数基本使用--如何将两个Excel表中的数据匹配:excel表中vlookup函数使用方法将一表引到另一表 一.将几个学生的籍贯匹配出来‘ 二.使用查找与引用函数 vlookup 三. ...
- tomcat启动(三)Catalina分析-load方法分析
load()方法按从上到下顺序分析(主要分析本人所没学过的知识点,其它略过...). Digester类作用 使用sax技术对xml进行解析 未开始解析时Digester.push(this)这个用来 ...
- 同源策略(same-origin policy)及三种跨域方法
同源策略(same-origin policy)及三种跨域方法 1.同源策略 含义: 同源是指文档的来源相同,主要包括三个方面 协议 主机 载入文档的URL端口 所以同源策略就是指脚本只能读取和所属文 ...
- 深入理解javascript函数系列第三篇——属性和方法
× 目录 [1]属性 [2]方法 前面的话 函数是javascript中的特殊的对象,可以拥有属性和方法,就像普通的对象拥有属性和方法一样.甚至可以用Function()构造函数来创建新的函数对象.本 ...
- .Net MVC 导入导出Excel总结(三种导出Excel方法,一种导入Excel方法) 通过MVC控制器导出导入Excel文件(可用于java SSH架构)
.Net MVC 导入导出Excel总结(三种导出Excel方法,一种导入Excel方法) [原文地址] 通过MVC控制器导出导入Excel文件(可用于java SSH架构) public cl ...
- Windows 8关机的三个最简单方法
Win8怎么关机?全新的Win8系统给用户一个难题,Win8如何关机?笔者整理了Win8关机的最实用的三个方法,希望能让大家了解Win8关机的具体操作,解决Win8如何关机等问题. 最常规的Win8关 ...
- CSS两列及三列自适应布局方法整理
布局 自适应 两列 三列 在传统方法的基础上加入了Flex布局并阐述各方法的优缺点,希望对大家有所帮助.先上目录: 两列布局:左侧定宽,右侧自适应 方法一:利用float和负外边距 方法二:利用外边距 ...
- JSON三种数据解析方法(转)
原 JSON三种数据解析方法 2018年01月15日 13:05:01 zhoujiang2012 阅读数:7896 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blo ...
- vue mandmobile ui实现三列列表的方法
vue mandmobile ui实现三列列表的方法 请问这种列表的要用那个组件好呢?Cellitem 只能用到两列,这个要三列的怎么弄?mand的好像没有listview,grid组件的 问了man ...
随机推荐
- 在C#编程中玩转枚举,分享我的EnumHelper。
在C#编程中玩转枚举,分享我的EnumHelper. 在软件开发过程中,我们经常会为特定的场景下的特定数据定义逻辑意义.比如在用户表中,我们可能会有一个用户状态字段,该字段为整形.如果该字段的值为1则 ...
- 2014阿里实习生面试题——mysql如何实现的索引
这是2014北京站的两副面孔阿里实习生问题扯在一起: 在MySQL中.索引属于存储引擎级别的概念,不同存储引擎对索引的实现方式是不同的,比方MyISAM和InnoDB存储引擎. MyISAM索引实现: ...
- sqlserver检测数据库是否能连接的小技巧
有时候可能需要检测下某台机器的服务是不是起来了,或者某台机器的某个库是不是能被连接又不能打开ssms也不想登陆服务器的话就可以用这个方法. 1.在桌面上右键创建个文本,然后改后缀名为udl以后保存(1 ...
- java抽象类和接口的区别(转载)
1.Java接口和Java抽象类最大的一个区别,就在于Java抽象类可以提供某些方法的部分实现,而Java接口不可以,这大概就是Java抽象类唯一的优点吧,但这个优点非常有用. 如果向一个抽象类里加入 ...
- C# 实现 Hyper-V 虚拟机 管理
原文:C# 实现 Hyper-V 虚拟机 管理 Hyper-V WMI Provider 工具类如下: "; break; } return status; } } /// <summ ...
- C#获取本机所有用户名
using System.DirectoryServices; using System.Runtime.InteropServices; (需要添加引用) [StructLayout(LayoutK ...
- lua迭代器和仿制药for
不管是什么样的结构,你只需要同意遍历集合可以称为迭代器的所有元素.lua常用来形容叙事功能迭代器.个元素.每个迭代器都须要保存一些状态来知道当前处于什么位置和怎样进行下一次迭代. 对于这种任务.闭包提 ...
- C# 通过扩展WebBrowser捕获网络连接错误信息
想捕获WebBrowser连接指定网站过程中发生的错误信息,包括网络无法连接.404找不到网页等等错误!经过网上的搜集,找到了以下解决方案,该解决方案不会在网站连接前发出多余的测试请求. 向Webbr ...
- 安装Windows2012操作系统 - 初学者系列 - 学习者系列文章
Windows 2012是微软最新的服务器操作系统,估计在国外服务器空间的运营商安装的比较多些吧.下面简要介绍下该操作系统的安装. 1. 将光盘放入光驱.进入BIOS设置成光驱启动.重启计算机. 2 ...
- WebService它CXF这三个音符(Service接口实现类)
ITeacherServiceImpl.java: /** * @Title:ITeacherServiceImpl.java * @Package:com.you.service.impl * @D ...