• 图的匹配问题与最大流问题(三)——最大流问题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;
    	}
    
    
    
    }
    



  • 相关阅读:
    darknet实时识别无法显示在窗口解决
    C# 获取当前打开的文件夹2
    C# 如何调试安装包
    C# 自定义文件格式并即时刷新注册表 非关闭explorer
    C# 获取当前打开的文件夹
    SQL Server里面导出SQL脚本(表数据的insert语句)
    windows平台安装redis服务
    C# 默认参数/可选参数需要注意
    webstrom使用
    office密匙
  • 原文地址:https://www.cnblogs.com/jiangu66/p/3184873.html
Copyright © 2020-2023  润新知