上篇文章主要介绍了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实现的更多相关文章

  1. Java进阶(三十六)深入理解Java的接口和抽象类

    Java进阶(三十六)深入理解Java的接口和抽象类 前言 对于面向对象编程来说,抽象是它的一大特征之一.在Java中,可以通过两种形式来体现OOP的抽象:接口和抽象类.这两者有太多相似的地方,又有太 ...

  2. vlookup函数基本使用--如何将两个Excel表中的数据匹配;excel表中vlookup函数使用方法将一表引到另一表

    vlookup函数基本使用--如何将两个Excel表中的数据匹配:excel表中vlookup函数使用方法将一表引到另一表 一.将几个学生的籍贯匹配出来‘ 二.使用查找与引用函数 vlookup 三. ...

  3. tomcat启动(三)Catalina分析-load方法分析

    load()方法按从上到下顺序分析(主要分析本人所没学过的知识点,其它略过...). Digester类作用 使用sax技术对xml进行解析 未开始解析时Digester.push(this)这个用来 ...

  4. 同源策略(same-origin policy)及三种跨域方法

    同源策略(same-origin policy)及三种跨域方法 1.同源策略 含义: 同源是指文档的来源相同,主要包括三个方面 协议 主机 载入文档的URL端口 所以同源策略就是指脚本只能读取和所属文 ...

  5. 深入理解javascript函数系列第三篇——属性和方法

    × 目录 [1]属性 [2]方法 前面的话 函数是javascript中的特殊的对象,可以拥有属性和方法,就像普通的对象拥有属性和方法一样.甚至可以用Function()构造函数来创建新的函数对象.本 ...

  6. .Net MVC 导入导出Excel总结(三种导出Excel方法,一种导入Excel方法) 通过MVC控制器导出导入Excel文件(可用于java SSH架构)

    .Net MVC  导入导出Excel总结(三种导出Excel方法,一种导入Excel方法) [原文地址] 通过MVC控制器导出导入Excel文件(可用于java SSH架构)   public cl ...

  7. Windows 8关机的三个最简单方法

    Win8怎么关机?全新的Win8系统给用户一个难题,Win8如何关机?笔者整理了Win8关机的最实用的三个方法,希望能让大家了解Win8关机的具体操作,解决Win8如何关机等问题. 最常规的Win8关 ...

  8. CSS两列及三列自适应布局方法整理

    布局 自适应 两列 三列 在传统方法的基础上加入了Flex布局并阐述各方法的优缺点,希望对大家有所帮助.先上目录: 两列布局:左侧定宽,右侧自适应 方法一:利用float和负外边距 方法二:利用外边距 ...

  9. JSON三种数据解析方法(转)

    原 JSON三种数据解析方法 2018年01月15日 13:05:01 zhoujiang2012 阅读数:7896    版权声明:本文为博主原创文章,未经博主允许不得转载. https://blo ...

  10. vue mandmobile ui实现三列列表的方法

    vue mandmobile ui实现三列列表的方法 请问这种列表的要用那个组件好呢?Cellitem 只能用到两列,这个要三列的怎么弄?mand的好像没有listview,grid组件的 问了man ...

随机推荐

  1. 事半功倍之StyleCop(一)

    事半功倍之StyleCop(一) 前言 曾几何时,你是否在看别人代码的时候总是在抱怨代码没有注释,命名不规范,代码风格不统一,代码可读性差?是否有一个适合团队开发规范的检查工具? 答案就是大名鼎鼎的S ...

  2. bootstrap基本标签总结2

    [布局]bootstrap基本标签总结2   缩略图 <div class="container"> <div class="row"> ...

  3. OpenStreetMap架构

    OpenStreetMap框架简介 1.OSM平台开发 OpenStreetMap(缩写OSM)地图是一个合作项目,我们的目标是创建一个免费的内容,让所有的人都可以编辑的世界地图. OSM在地图上由一 ...

  4. SqlServer-COMPUTE BY

    原文:SqlServer-COMPUTE BY COMPUTE BY子句可以通过同一个select语句即查看明细行,又查看汇总行.可以计算子组的汇总值,也可以计算整个结果集的汇总值 COMPUTE 子 ...

  5. 反射调用方法报InvocationTargetException异常

    利用 Method 对象的 invoke 方法调用目标对象的方法时, 若在目标对象的方法内部抛出异常, 会被包装成 InvocationTargetException 异常抛出,  可以通过调用 In ...

  6. [译]ava 设计模式之构造器

    (文章翻译自Java Design Pattern: Builder) 构造器模式的关键之处在于它使用一步接招一步的流程去构建东西,例如:尽管构建的每一步是不相同的但是每一个产品还是遵循相同的流程. ...

  7. zepto.js的基本介绍与使用

    最近看到了一篇文章,是介绍一种新的js框架,名为zepto.js,他适用于移动设备已经桌面浏览器除了ie系列的.. 他兼容jquery的API,所以学起来或用起来并不吃力.他比jquery的优势在于1 ...

  8. C#函数式程序设计之泛型

    Intellij修改archetype Plugin配置 2014-03-16 09:26 by 破狼, 204 阅读, 0 评论,收藏, 编辑 Maven archetype plugin为我们提供 ...

  9. iOS基础 - 触摸事件&手势识别

    ================================================================== 一.触摸事件&手势识别 1> 4个触摸事件,针对视图 ...

  10. REDGATE又一好用的脚本工具

    REDGATE又一好用的脚本工具   REDGATE又一好用的脚本工具 先说明一下:这个工具是免费的 下载地址:http://www.red-gate.com/products/dba/sql-scr ...