c2java 第8篇 网络流

本文介绍了Edmonds-Karp算法的原理及应用,该算法通过广度优先搜索寻找增广路径,实现最大流问题的高效解决。文中还探讨了算法的具体实现细节,并给出了几个典型的应用场景,包括液体管道流动、电路电流分析等。
Edmonds-Karp 算法: 使用bfs找增广路经,复杂度min(O(VE^2), O(EF)), 其中F是最大流的流量. 依据是
最大流最小割定理:
1. 对于任一流f和任一割c, 流量|f| = |c| <= c的容量。
2. f 是最大流 <==> 残留网络Gf没有增广路径 <==> 存在一个割,其容量等于f的流量。


应用例子
====
liquids in pipes, parts through assembly lines, current throw electrical networks.
1. 求一个无向图的边连通度, 意思是只有至少去掉k条边才能使得图不连通。例如树的边连通度为1,圈的为2。
答案就是最大流对应的最小割。


2. 二分图的最大匹配。
答案: 设图顶点分成L和F两部分,L 到F 的边容量是1, 增加两个顶点s到L, R到t,
容量为无穷大。


3. 最少路径覆盖所有顶点。minimum path cover.


语言注记
====
1. 如果Type是非基本类型,则Type[][] t = new Type[10][2] 实际相当于void* t[10][2] 与Type本身没有关系;
因此对于每个t[i][j] 都要new, 这里的问题是,new次数多了内存碎片影响有多大?
如果容量是整数,直接把v,cap,flow,res 编码为t[4*i+0, ..., 4*i+3]好了。


2. 下面加了一个iterator对象,这样做的最大好处是让上层应用不依赖底层的表示;以后如果换成链表上层

什么都不用改。

 代码:

 

/*Flow Network
*/
import java.util.*;
import java.io.*;

class Edge
{
	int v; /*临接顶点*/
	int cap; /*边的容量, -1表示非原始边*/
	int flow; /*边上的流量*/
	int res; /*边的残余容量*/
}

public class Flow{
int n; /*顶点数*/
Edge[][] edges; /*临接表*/
int[] degree; /*临接的边数*/
int[] parents; /*记录路径*/
int source, sink; 

class EdgeIterator implements Iterator {
	Edge[] e;
	int deg;
	int i;
	public EdgeIterator(int v){
		e = edges[v];
		deg = degree[v];	
		i = 0;
	}

	public boolean hasNext(){
		return i < deg;
	}
	public Edge next(){
		return e[i++];
	}

	public void remove(){
		System.out.println("not impl");
	}

}
public Iterator iterator(int v){
	return new EdgeIterator(v);
}

public Flow(int vertexNum, int edgeNum, Scanner in) throws IOException
{
	int i, j;

	n = vertexNum;
	edges = new Edge[n][10];
	for(i = 0; i < n; ++i){
		for(j = 0; j < edges[i].length; ++j)
			edges[i][j] = new Edge();
	}
	degree = new int[n];
	parents = new int[n];
	

	source = in.nextInt(); sink = in.nextInt();
	while(edgeNum-- > 0){
		int u, v, c;
		u = in.nextInt(); v = in.nextInt(); c = in.nextInt();
		addEdge(u, v, c);
	}
}

void ensureCapacity(int v)
{
	int i;
	if(degree[v] >= edges[v].length){
		edges[v] = Arrays.copyOf(edges[v], degree[v] + 10);	
		for(i = degree[v]; i < degree[v] + 10; ++i){
			edges[v][i] = new Edge();
		}
	}
}

void addEdge(int i, int j, int capacity)
{/*增加边并同时构建残余边*/
	Edge a, b;
	int flow = 0; /*初始流量*/
	ensureCapacity(i);
	a = edges[i][degree[i]++];
	a.v = j;
	a.flow = flow;
	a.res = capacity - a.flow;
	a.cap = capacity;
	
	ensureCapacity(j);
	b = edges[j][degree[j]++];
	b.v = i;
	b.flow = flow;
	b.res = b.flow;
	b.cap = -1;
}

Edge findEdge(int x, int y)
{
	int i;
	for(i = 0; i < degree[x]; ++i)
		if(edges[x][i].v == y)
			return edges[x][i];
	return null;
}

void dumpFlows()
{
	int i, j;
	Edge e;
	System.out.printf(" f/c:%n");
	for(i = 0; i < n; ++i){
		Iterator iter = iterator(i); 
		while(iter.hasNext()){
			e = iter.next();
		//for(j = 0; j < degree[i]; ++j){
			//e = edges[i][j];
			if(e.cap > 0)System.out.printf("
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值