Algorithms Part II Maxflow 笔记

11 篇文章 0 订阅

MinCut

初始化是一个edge-weighted digraph, 有一个源点是s, 和目标点t;
st-cut(cut)/ 割:将digraph的点分为两个不相连的集合,s在一个集合A,t在一个集合B;
Capacity 从集合A到B的所有edge的容量总和;
在这里插入图片描述
mincut : 拥有最小capacity的割问题;

MaxFlow

flow : 流,1. 小于等于该边容量;2. 输入流和输出流必须相等(除了s和t,在有向图中,假设s只有输出,t只有输入);

##最大流问题就是找到输入目标终点的最大流;
在这里插入图片描述

以上是几个定义

FF Algorithm

  1. 所有flow初始化为0;
  2. 寻找从s到t的无向路径,包括向前和向后的edge;无向路径必须满足:(1)在前进路径中,flow可以增加,edge不能满;(2)在反向路径中,flow可以减少,edge不能空;(个人理解是在反流情况下,需要以当前点流入的flow减去正向流入的flow,剩下的flow进行反流,如下图)

在这里插入图片描述
以下是一个更复杂的情况
在这里插入图片描述
在上图中,在先前的遍历中,只有b-c还没有flow流过,所以是空的;因为flow必须小于等于容量,所有增加c-d的容量,本来是5,现在增加为8,相应的s-a,a-b,b-c各增加到3;因为c-d增加了3,为了保证d点的inflow控制在10(因为outflow是10,inflow=outflow);需要回流3, 所以d-e的flow = 5 - 3。

  1. 当没有增长路径时,terminate;(如何判定没有增长路径:所有从s-t的路径都已经锁住了,也就是每一条augmenting path都同时包含一条full的前edge或者空的backward edge, 意思就是不能加了也不能减了);

FF算法用pq和bfs或者dfs都可以简单的实现

最大流最小割定理

定义:从cut A和cut B流过的净流量 = A-B的所有边流量之和 - B-A的所有边流量之和;
flow-value 定理: A-B的净流量 = f;(f是任意一条flow);
(任意两个割A和B, 净流量很好理解,A流过去的减去流回来的就是net flow;value是流入目标点t的flow, 因为s在cut A, t在cut B, 所以净流量 = f)
在这里插入图片描述

增广路径定理
如果没有增广路径存在了,那么此时的流就是最大流;
最大流最小割定理
最大流 = 最小割的容量

通过最大流来计算最小割

  1. 通过增广路径定理,对于最大流f,已经没有增广路径存在;
  2. s所在的集合A,没有空的反向路径和满的正向路径;
    (个人理解:判断没有增广路径的条件是每一条增广路径都包含了空的反向路径或者满的正向路径,那么此时,A中没有这两种情况,连接A和B的edge必定是满的正向或者空的反向,空的反向路径不用去看,因为流入不到最终目标点t,正向路径的flow加起来,就是最终流入目标点t的maxflow!)
    在这里插入图片描述

4. Running time analysis

#FF算法是基于整数情况下的
重要特征: 增广路径个数 <= the value of maxflow;

Integrality theroem : 存在整数形式的maxflow;(最坏情况是增广路径等于maxflow,每次增加1的情况下,maxflow可能呈指数形式);

复杂度分析:
在这里插入图片描述

5. JAVA Implementation

  • 对于一条edge, v -> w; 如果是前向, 那么residual flow = capacity - flow;
  • 如果是逆向的,那么residual flow = flow;
  • flow的增加就是正向加反向减、

然后我们可以用residual network来处理graph

在这里插入图片描述
Flow API

public class FlowEdge {

	private final int v, w;
	private final double capacity;
	private double flow;

	public FlowEdge(int v, int w, double capacity) {
		this.v = v;
		this.w = w;
		this.capacity = capacity;
	}
	from(){}
	to();
	......
	public int other(int vertex) {
		if (vertex == v) return w;
		if (vertex == w) return v;
		else throw new IllegalAccessException();
	}
	public double residualCapacityTo(int vertex) {
		if (vertex == v) return flow;
		if (vertex == w) return capacity - flow;
		else throw new IllegalAccessException();
	}
	public void addResidualFlowTo(int vertex, double delta) {
		if (vertex == v) flow -= delta;
		else if (vertex == w) flow += delta;
		else throw new IllegalArgumentException();
	}

}

Flow network API

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 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;

	public FordFulkerson(FlowNetWork G, int s, int t) {
		value = 0.0;
		while (hasAugmentingPath(G, s, t)) {
			double bottle = Double.POSITIVE_INFINITY;
			for (int v = t; v != s; v = edgeTo[v].other[v]) {
				bottle = Math.min(bottle, edgeTo[v].residualCapacityTo(v));
			}
			for (int v = t; v != s; v = v.edgeTo[v].other(v)) {
				edgeTo[v].addResidualFlowTo(v, bottle);
			}
			value += bottle;
		}
	}
	// residual network
	private boolean hasAugmentingPath(FlowNetWork G, int s, int t) {
		edgeTo = new FlowEdge[G.V()];
		marked = new boolean[G.V()];

		Queue<Integer> queue = new Queue<Integer>();
		marked[s] = true;
		while (!queue.isEmpty()) {
			for (FlowEdge e: G.adj(v)) {
				int w = e.other(v);
				if (e.residualCapacityTo(w) > 0 && !marked[w]) {
					edgeTo[w] = e;
					marked[w] = true;
					queue.enqueue(w);
				}
			}
		}
	}
}

(algorithms的方法名称非常直观。。。不过for-loop的方式很奇怪)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值