Coursera Algorithm, Part2 Week3: MaxFlow

week3的作业太难了,已经花了好长时间了(读题目、理解题目,算上零零碎碎的时间,都好几天了 - -)。还是先写下blog总结归纳下这周的工作吧,也为以后回顾方便些。

csdn大姨妈了!!!!先是把我写了一晚上加一上午的blog整得成类似源码的形式了,图片什么的都没有了,只得重新写啊!接着,写blog的链接怎么也访问不了,靠!!



1. 最小割问题

对于一个带权重的有向图中(权值这里称为capacity),图中包含一个源节点s和一个目标节点t,如下图所示:


定义:

(1)源节点s和目标节点t的一个切割就是将该有向图中的节点进行划分,使s在集合A中、t在集合B中。

(2)该切割的capacity即由集合A指向集合B的所有边的capacity(由B指向A的边不计算在内)。

最小割的问题就是找到这样的划分使得切割的capacity最小化。上图的切割可以如下(最后一个为最小割):

 O.O 



2. 最大流问题

与最小割问题的初始条件类似,每条边上增加了流的概念,问题的描述就更加顾名思义了:




3. Ford-Fulkerson algorithm

Ford-Fulkerson algorithm是解决最大流问题的一种算法,算法描述如下;

Start with 0 flow
While there exists an augmenting path:
	- find an augmenting path
	- compute bottleneck capacity
	- increase flow on that path bu bottleneck capacity
详细描述如下的几个阶段:

step1:初始化流网络,置flow=0。


step2:在流网络中寻找由源节点s到目标节点t的一条路径,当然包括普通的路径和增广路径,是一个迭代的过程。总体看来,路径中包含这样的边:未满(flow未达到capacity)的forward边和非空的backword边。


@-@


@-@


@-@


step3:无法再找到从s到t的路径(forward边都满,backward边都空),结束迭代。


所有的问题都指向如何寻找增广路径:BFS可以轻松解决这个问题。

另外,还有几个有用的结论:

(1)最大流等于最小割容量。

(2)流达到最大流的条件当且仅当无增广路径。

(3)由最大流计算最小割(A, B):同样BFS解决。首先,带权有向图中再找不到增广路径;那么集合A就是从源节点s出发,依次经过非满的forward边或者非空的backward边访问节点,直至闭合。


4. Ford-Fulkerson algorithm 实现

4.1 残余网络

对于已经有网络流的图,一条边上的流f,容量c,则该条边上的残余量为c-f。增广路径是建立在残余网络基础上的,可以对残余网络有如下的构想:


4.2 数据结构

引入新的数据结构,包括边和图,但都是构建在之前的提出的边和图的数据结构之上的。边的数据结构包括了流和容量的概念,图的数据结构与有向图略有不同。具体还是看实现吧。

public class FlowEdge {

	private final int v, w;              // from and to
	private final int double capacity;   // capcacity
	private double flow;                 // flow, flow variable

	public FlowEdge(int v, int w, double capacity) {

		this.v = v;
		this.w = w;
		this.capacity = capacity;
	}

	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;
		else throw new RuntimeException("Illegal endpoint");
	}

	public double residualCapacityTo(int vertex) {
		if (vertex == v) return flow;                // backward edge
		else if (vertex == w) return capacity-flow;  // forward edge
		else throw new IllegalArgumentException();
	}

	public void addResidualFlowTo(int vertex, double delta) {
		if (vertex == v) flow -= delta;              // backward
		else if (vertex == w) flow += delta;         // forward
		else throw new IllegalArgumentException();
	}
}
public class FlowNetwork {
	
	private final int V;
	private Bag<FlowEdge>[] adj;

	public FlowNetwork(int V) {
		
		this.V = V;
		adj = (Bag<FlowEdge>[]) new Bag[V];
		for (int v = 0; v < V; v++)
			adj[v] = new Bag<FlowEdge>();
	}

	public void addEdge(FlowEdge e) {

		int v = e.from();
		int w = e.to();
		adj[v].add(e);
		adj[w].add(e);
	}

	public Iterable<FlowEdge> adj(int v) {
		return adj[v];
	}
}

4.3 算法实现

根据伪代码给出的算法思想,每次迭代找一条由s到t的路径,找到这条路径上可增量的最大值,依次对该条路径上的每条边相应增量(forward边值增加,backward边值减少)。而找一条s到t的路径通过BFS实现,从源节点s开始BFS看能否到达目标节点t,满足BFS的条件是经过的该条边forward边未满或backward边非空。

话不多说,贴代码:

public class FordFulkerson {
	
	private boolean[] marked;     // true if s->v path in residual network
	private FlowEdge[] edgeTo;    // last edge on s->v path
	private double value;         // value of flow

	public FordFulkerson(FlowEdge G, int s, int t) {

		value = 0.0;
		while (hasAugmentingPath(G, s, t)) {
			double bottle = Double.POSITIVE_INFINITY;
			// compute bottleneck capacity
			for (int v = t; v != s; v = edgeTo[v].other(v))
				bottle = Math.min(bottle, edgeTo[v].residualCapacity(v));

			// augment flow
			for (int v = t; v != s; v = edgeTo[v].other(v))
				edgeTo[v].addResidualFlowTo(v, bottle);

			value += bottle;
		}
	}

	public boolean hasAugmentingPath(FlowNetwork G, int s, int t) {

		edgeTo = new FlowEdge[G.V()];
		marked = new boolean[G.V()];

		Queue<Integer> queue = new Queue<Integer>();
		queue.enqueue(s);
		marked[s] = true;
		while (!queue.isEmpty()) {
			int v = queue.dequeue();

			for (FlowEdge e : G.adj(v)) {
				int w = e.other(v);
				// found path from s to w in the residual network
				if (e.residualCapacity(w) > 0 && !marked[w]) {
					edge[w] = e;          // save last edge on path to w
					marked[w] = true;     // mark w
					queue.enqueue(w);     // add w to the queue
				}
			}
		}

		return marked[t];     // is t reachable from s in residual network
	}

	public double value() {
		return value;
	}

	// is v reachable from s in residual network
	public boolean inCut(int v) {
		return marked[v];
	}
}

不容易啊,顶着做不出week3作业的压力硬是把blog给写了(对于我这样一个有强迫症的人来说,不把一件事完成是绝不会去做另一件事的)。而且这篇blog花了一晚上加一整天啊,被坑坑的csdn折腾得不行了,这篇blog相当于是写了两遍了的,艰难不堪。


我会成功吗,我会在这一点点的积累中、一步一步的艰难前行中成就吗?我真的不知道,我希望现实能够像梦想一样美好,但是我不敢奢求,唯恐我承受的苦难还不够,还没到让我成功的时候。也许我会失望,不后悔吧。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值