Ford-Fulkerson算法求最大流Java实现

在最大流问题中,我们希望在不违反任何容量限制的情况下,计算出从源结点到汇点的最大流速。对于流网络中的每一个结点,遵守“流量守恒”:除了源结点与汇点之外,流入该结点的速率等于流出该结点的速率。

《算法导论》书中所给出的伪代码如下所示:


下面是一个求最大流的过程



下面是用Java的代码实现:

package Ford_Fulkerson;
/**
 * 网络中的边
 * @author sdu20
 *
 */
public class Edge {

	private int v1;
	private int v2;
	private int capacity;
	private int flow;
	
	public Edge(int v1,int v2,int flow,int capacity){
		this.v1 = v1;
		this.v2 = v2;
		this.capacity = capacity;
		this.flow = flow;
	}
	
	public int getV1(){
		return v1;
	}
	
	public int getV2(){
		return v2;
	}
	
	public int getCapacity(){
		return capacity;
	}
	
	public int getFlow(){
		return flow;
	}
	
	public void setFlow(int f){
		flow = f;
	}
}

package Ford_Fulkerson;
/**
 * 残存网络中的边
 * @author sdu20
 *
 */
public class Edge2 {
	private int v1;
	private int v2;
	private int flow;
	
	public Edge2(int v1,int v2,int flow){
		this.v1 = v1;
		this.v2 = v2;
		this.flow = flow;
	}
	
	public int getV1(){
		return v1;
	}
	
	public int getV2(){
		return v2;
	}
	
	public int getFlow(){
		return flow;
	}
	
	public void setFlow(int f){
		flow = f;
	}

}

package Ford_Fulkerson;
import java.util.*;
/**
 * 残存网络Gf
 * @author sdu20
 *
 */
public class Gf {

	private int vNum;
	private int eNum;
	private LinkedList<Edge2>[] GLists;
	
	public Gf(int n){
		vNum = n;
		eNum = 0;
		GLists = new LinkedList[n];
		
		for(int i = 0;i<n;i++)
			GLists[i] = new LinkedList<>();
	}
	
	public void insertEdge(Edge2 e){
		int v1 = e.getV1();
		GLists[v1].add(e);
		eNum++;
	}
	
	/**
	 * 返回一条增广路径
	 * @return
	 */
	public LinkedList<Integer> augmentingPath(){
		
		LinkedList<Integer> list = new LinkedList<>();
		Queue<Integer> queue = new LinkedList<>();
		int[] reached = new int[vNum];
		int[] preNode = new int[vNum];
		for(int i = 0;i<vNum;i++){
			reached[i] = 0;
			preNode[i] = -1;
		}
		preNode[0] = -1;
		
		reached[0] = 1;
		queue.add(0);
		while(!queue.isEmpty()){//没有循环起来
			int now = queue.poll();
			
			LinkedList<Edge2> inlist = (LinkedList<Edge2>) GLists[now].clone();
			
			while(!inlist.isEmpty()){
				
				Edge2 e = inlist.pop();
				int v2 = e.getV2();
				
				if(reached[v2]==0){
					queue.add(v2);
					reached[v2] = 1;
					preNode[v2] = now;
				}
			}
		}
		
		for(int i = 0;i<vNum;i++){
			System.out.println(reached[i]+"     "+preNode[i]);
		}
		
		if(reached[vNum-1]==0){
			//System.out.println("here");
			return list;
			
		}
		
		int pointnum = vNum-1;
		while(pointnum!=-1){
			list.add(0, pointnum);
			pointnum = preNode[pointnum];
		}
				
		return list;
	} 
	
	/**
	 * 根据增广路径得到需要调整的值
	 * @param list
	 * @return
	 */
	public int changeNum(LinkedList<Integer> list){
		if(list.equals(null))
			return 0;
		int minchange = 1000;
		int v1 = 0;
		for(int i = 1;i<list.size();i++){
			int v2 = list.get(i);
			LinkedList<Edge2> elist = (LinkedList<Edge2>) GLists[v1].clone();
			Edge2 edge = elist.pop();
			while(edge.getV2()!=v2){
				edge = elist.pop();
			}
			if(minchange>edge.getFlow())
				minchange = edge.getFlow();
			
			v1 = v2;
		}
		
		return minchange;
	}
	
	public void bianli(){
		System.out.println("残存网络 共 "+vNum+" 个顶点, "+eNum+" 条边");
		for(int i = 0;i<vNum;i++){
			if(GLists[i].size()==0){
				System.out.println(i+"没有后继");
				continue;
			}
			for(int j = 0;j<GLists[i].size();j++){
				Edge2 e = GLists[i].get(j);
				System.out.println("[ "+e.getV1()+" , "+e.getV2()+" , "+e.getFlow()+" ]");
			}
		}
	}
}

package Ford_Fulkerson;
import java.util.*;
/**
 * 流网络
 * @author sdu20
 *
 */
public class Graph {
	
	private int vNum;
	private int eNum;
	private Gf gf;
	private LinkedList<Edge>[] GLists;
	
	public Graph(int n){
		vNum = n;
		eNum = 0;
		GLists = new LinkedList[n];
		
		for(int i = 0;i<n;i++)
			GLists[i] = new LinkedList<>();
	}
	
	public void insertEdge(Edge e){
		int v1 = e.getV1();
		GLists[v1].add(e);
		eNum++;
	}
	
//	public void deleteEdge(Edge e){
//		int v1 = e.getV1();
//		int v2 = e.getV1();
//		
//	}
	
	public void produceGf(){
		gf = new Gf(vNum);
		
		for(int i = 0;i<vNum;i++){
			LinkedList<Edge> list = (LinkedList<Edge>) GLists[i].clone();
			
			while(!list.isEmpty()){
				
				Edge edge = list.pop();
				int v1 = edge.getV1();
				int v2 = edge.getV2();
				int flow = edge.getFlow();
				int capacity = edge.getCapacity();
				
				if(flow==0){
					gf.insertEdge(new Edge2(v1,v2,capacity));
				}else{
					if(flow==capacity){
						gf.insertEdge(new Edge2(v2,v1,capacity));
					}else if(flow<capacity){
						gf.insertEdge(new Edge2(v1,v2,capacity-flow));
						gf.insertEdge(new Edge2(v2,v1,flow));
					}
				}
			}
		}
	}
	
	public Gf getGf(){
		return gf;
	}
	
	private LinkedList<Integer> augmentingPath(){
		return gf.augmentingPath();
	}
	
	private int changeNum(LinkedList<Integer> list){
		return gf.changeNum(list);
	}
	
	/**
	 * 最大流
	 */
	public void MaxFlow(){
		produceGf();
		gf.bianli();
		LinkedList<Integer> list = augmentingPath();
		
		while(list.size()>0){
			
			int changenum = changeNum(list);
			
			LinkedList<Integer> copylist = (LinkedList<Integer>) list.clone();//调试
			System.out.println("list:");
			while(!copylist.isEmpty()){
				System.out.print(copylist.pop()+"  ");
			}
			System.out.println();
			System.out.println("changenum: "+changenum);
					
			int v1 = 0;
			for(int i = 1;i<list.size();i++){
				int v2 = list.get(i);
				if(!GLists[v1].isEmpty()){
					int j = 0;
					Edge e = GLists[v1].get(j);
					while(e.getV2()!=v2 && j<GLists[v1].size()){
						e = GLists[v1].get(j);
						j++;						
					}
					if(e.getV2()!=v2 && j==GLists[v1].size()){//调试
						j = 0;
						e = GLists[v2].get(j);
						while(e.getV2()!=v1 && j<GLists[v2].size()){
							e = GLists[v2].get(j);
							j++;
						}
						
					}
					e.setFlow(e.getFlow()+changenum);
				}
				v1  = v2;
				
			}
			bianli();	
			produceGf();
			gf.bianli();
			list = augmentingPath();
		}
	}
	
	public void bianli(){
		System.out.println("共有 "+vNum+" 个顶点, "+eNum+" 条边");
		for(int i = 0;i<vNum;i++){
			if(GLists[i].size()==0)
				continue;
			for(int j = 0;j<GLists[i].size();j++){
				Edge e = GLists[i].get(j);
				System.out.println("[ "+e.getV1()+" , "+e.getV2()+" , "+e.getFlow()+" , "+e.getCapacity()+" ]");
			}
		}
	}
	
	public void showResult(){
		bianli();
		int maxflow = 0;
		
		for(int i = 0;i<vNum;i++){
			if(GLists[i].size()>0){
				for(int j = 0;j<GLists[i].size();j++){
					if(GLists[i].get(j).getV2() == vNum-1){
						maxflow += GLists[i].get(j).getFlow();
					}
				}
			}
		}
		System.out.println("最大流为 "+maxflow);
			
	}

}

package Ford_Fulkerson;

public class Main {

	public static void main(String[] args){		
		test();
	}
	
	private static void test(){
		Graph graph = new Graph(6);
		Edge[] edges = new Edge[9];
		
		edges[0] = new Edge(0,1,0,16);
		edges[1] = new Edge(0,2,0,13);
		edges[2] = new Edge(1,3,0,12);
		edges[3] = new Edge(2,1,0,4);
		edges[4] = new Edge(2,4,0,14);
		edges[5] = new Edge(3,2,0,9);
		edges[6] = new Edge(3,5,0,20);
		edges[7] = new Edge(4,3,0,7);
		edges[8] = new Edge(4,5,0,4);
		
		for(int i = 0;i<9;i++)
			graph.insertEdge(edges[i]);
		
		graph.MaxFlow();
		graph.showResult();
	}
	
	public static void test2(){
		Graph graph = new Graph(6);
		
		Edge[] edges = new Edge[9];
		edges[0] = new Edge(0,1,4,16);
		edges[1] = new Edge(0,2,0,13);
		edges[2] = new Edge(1,3,4,12);
		edges[3] = new Edge(2,1,0,4);
		edges[4] = new Edge(2,4,4,14);
		edges[5] = new Edge(3,2,4,9);
		edges[6] = new Edge(3,5,0,20);
		edges[7] = new Edge(4,3,0,7);
		edges[8] = new Edge(4,5,4,4);
		
		for(int i = 0;i<9;i++)
			graph.insertEdge(edges[i]);
		
		graph.bianli();
		
		graph.MaxFlow();
		graph.bianli();
	}
}

运行截图如下


  • 5
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Ford-Fulkerson算法最大流问题的一种经典算法。以下是一个基于增广路思想的Ford-Fulkerson算法的代码: ``` // 基于邻接矩阵的Ford-Fulkerson算法实现 #include <iostream> #include <queue> #include <cstring> using namespace std; const int MAXN = 100; // 最大顶点数 const int INF = 0x3f3f3f3f; // 表示无穷大 int n, m; // n表示顶点数,m表示边数 int s, t; // s表示源点,t表示汇点 int cap[MAXN][MAXN]; // 表示容量 int flow[MAXN][MAXN]; // 表示流量 int pre[MAXN]; // 表示前驱节点 int bfs() { memset(pre, -1, sizeof(pre)); // 初始化前驱节点数组 queue<int> q; q.push(s); pre[s] = -2; while (!q.empty()) { int u = q.front(); q.pop(); for (int v = 0; v < n; ++v) { if (pre[v] == -1 && cap[u][v] > flow[u][v]) { pre[v] = u; if (v == t) return 1; q.push(v); } } } return 0; } int maxFlow() { int ans = 0; while (bfs()) { int minflow = INF; for (int u = t; u != s; u = pre[u]) { int v = pre[u]; minflow = min(minflow, cap[v][u] - flow[v][u]); } for (int u = t; u != s; u = pre[u]) { int v = pre[u]; flow[v][u] += minflow; flow[u][v] -= minflow; } ans += minflow; } return ans; } int main() { cin >> n >> m >> s >> t; memset(cap, 0, sizeof(cap)); memset(flow, 0, sizeof(flow)); for (int i = 0; i < m; ++i) { int u, v, c; cin >> u >> v >> c; cap[u][v] += c; // 注意有可能存在重边 } cout << maxFlow() << endl; return 0; } ``` 算法思路: 1. 初始化流量为0; 2. 在剩余容量大于0的情况下,寻找增广路: - 从源点s开始,使用BFS寻找一条增广路; - 如果找到增广路,计算增广路上的最小剩余容量minflow,更新流量; 3. 最大流就是所有增广路上的最小剩余容量之和。 其中,增广路的定义是指从源点到汇点路径上,剩余容量均大于0的路径。在Ford-Fulkerson算法中,每次都需要寻找一条增广路来更新流量,直到无法再找到增广路为止。这个过程中,每次找到的增广路都可以使得流量增加,因此最终的流量是不断增加的。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值