网络流

本文介绍了最大流问题的基本概念,包括容量、流量和残流量等,并详细解释了增广路算法(EK算法)的工作原理及实现过程。通过三个具体的POJ题目实例展示了算法的应用。

1。最大流问题

即给定源点s和汇点t, 求s到t的最大流.

几个名词:

(1).容量(capacity): 对于一条边(u,v),它的物品上线称为容量,记作C(u,v),对于不存在的边C(u,v)=0

(2).流量(flow): 实际运送的物品称为流量,记作F(u,v),且F(u,v) = -F(v,u),所有F(u,v)最多只有一个为整数(可以都是0)

(3).残流量: 容量与流量之差称为残流量(简称残量)

在最大流问题中, 容量C和流量F满足3个性质:

(1).容量限制: F(u,v) <= C(u,v)

(2).斜对称性: F(u,v) = -F(v,u)

(3).流量平衡: 即从s点流出的净流量 == 流入t的净流量

求最大流问题的经典算法——增广路算法(EK算法)

注:这里我用自己的想法描述,以书本为准!!

每次找出从s到t的一条道路的最小残量d, 把对应边的流量减去d,所求的最大流max+=d;

直到整个网络中存在的道路其最小残量值都为0, 则表示已经是最大流了.

练习:

poj 1459 Power Network

http://162.105.81.212/JudgeOnline/problem?id=1459

import java.io.BufferedInputStream; import java.io.FileNotFoundException; import java.util.Arrays; import java.util.LinkedList; import java.util.Scanner; public class Main { public static void main(String[] args) throws FileNotFoundException { Scanner in = new Scanner(new BufferedInputStream(System.in)); final int INF = 10000001; final int MAX = 105; int n, np, nc, m, i, u, v, w, s, t, ret; //a[i]表示从源点s到每个节点i的路径上的最小残量,可得a[i]>=0,所以可用a[i]来替代visted[i] int a[] = new int[MAX], capacity[][] = new int[MAX][MAX], flow[][] = new int[MAX][MAX], path[] = new int[MAX]; String str, tmp; while(in.hasNext()) { n = in.nextInt(); s = n; //网络流源点 t = n + 1; //网络流汇点 np = in.nextInt(); nc = in.nextInt(); m = in.nextInt(); for(i=0; i<=t; i++) { Arrays.fill(flow[i], 0); Arrays.fill(capacity[i], 0); } for(i=0; i<m; i++) { str = in.next(); tmp = str.substring(1, str.indexOf(',')); u = Integer.parseInt(tmp); tmp = str.substring(str.indexOf(',')+1, str.lastIndexOf(')')); v = Integer.parseInt(tmp); tmp = str.substring(str.lastIndexOf(')')+1); w = Integer.parseInt(tmp); capacity[u][v] = w; //u->v的最大流量为w; } for(i=0; i<np; i++) { str = in.next(); tmp = str.substring(str.indexOf('(')+1, str.lastIndexOf(')')); v = Integer.parseInt(tmp); tmp = str.substring(str.lastIndexOf(')')+1); w = Integer.parseInt(tmp); capacity[s][v] = w; //源->v } for(i=0; i<nc; i++) { str = in.next(); tmp = str.substring(str.indexOf('(')+1, str.lastIndexOf(')')); u = Integer.parseInt(tmp); tmp = str.substring(str.lastIndexOf(')')+1); w = Integer.parseInt(tmp); capacity[u][t] = w; //u->汇点 } //EK算法 ret = 0; LinkedList<Integer> Que = new LinkedList<Integer>(); while(true) { Arrays.fill(a, 0); a[s] = INF; Que.addLast(s); while(!Que.isEmpty()) { u = Que.getFirst(); Que.removeFirst(); for(v=0; v<=t; v++) { if(a[v] == 0 && capacity[u][v] > flow[u][v]) { path[v] = u; Que.addLast(v); a[v] = a[u] > capacity[u][v]-flow[u][v] ? capacity[u][v]-flow[u][v] : a[u]; } } } if(a[t] == 0) //如果最小残量为0, 则表示已经是最大流了. break; for(u=t; u!=s; u=path[u]) { flow[path[u]][u] += a[t]; flow[u][path[u]] -= a[t]; } ret += a[t]; //ret为最大流量 } System.out.println(ret); } } }

poj 1273 Drainage Ditches

http://162.105.81.212/JudgeOnline/problem?id=1273

题目要看清楚...cap[A][B] += C;

最好用bfs, dfs很容易被搞死.

#include<iostream> #include<queue> using namespace std; #define INF 0x7fffffff int main() { //freopen("in.txt", "r", stdin); int N, M, s, t, A, B, C, ret; int cap[202][202], flow[202][202], path[202], a[202]; while(scanf("%d%d", &N, &M) != EOF) { s = 1; t = M; memset(cap, 0, sizeof(cap)); memset(flow, 0, sizeof(flow)); while(N--) { scanf("%d%d%d", &A, &B, &C); cap[A][B] += C; } //EK ret = 0; queue<int> Que; while(1) { memset(a, 0, sizeof(a)); a[s] = INF; while(!Que.empty()) Que.pop(); Que.push(s); while(!Que.empty()) { int u = Que.front(); Que.pop(); for(int v=1; v<=M; v++) { if(!a[v] && cap[u][v] > flow[u][v]) { path[v] = u; Que.push(v); a[v] = a[u] > cap[u][v] - flow[u][v] ? cap[u][v] - flow[u][v] : a[u]; if(v == t) break; } } } if(!a[t]) break; for(int u=t; u!=s; u=path[u]) { flow[path[u]][u] += a[t]; flow[u][path[u]] -= a[t]; } ret += a[t]; } printf("%d/n", ret); } return 0; }

poj 1149 PIGS

http://162.105.81.212/JudgeOnline/problem?id=1149

注意建图

#include<iostream> using namespace std; #define INF 0x7fffffff #define min(a,b) a>b?b:a int S, T, M, N; int room[1001], belong[1001], cap[103][103], pre[103], flow[103], Que[103]; int bfs() { int i, v, u, front, last; for(i=S; i<=T; i++) { flow[i] = INF; pre[i] = -1; } pre[S] = 0; Que[0] = S; front = 0; last = 1; while(front != last) { v = Que[front++]; for(u=1; u<=T; u++) { if(u==S || pre[u]!=-1 || cap[v][u]==0) continue; pre[u] = v; flow[u] = min(flow[v], cap[v][u]); Que[last++] = u; } } if(flow[T] == INF) return -1; else return flow[T]; } //EK int EK() { int now, last,tmp, ret = 0; while(1) { if((tmp = bfs()) == -1) break; ret += tmp; now = T; while(now != S) { last = now; now = pre[now]; cap[now][last] -= tmp; cap[last][now] += tmp; } } return ret; } int main() { //freopen("in.txt", "r", stdin); int i, j, t, num; while(scanf("%d%d", &M, &N) != EOF) { S = 0; T = N + 1; memset(cap, 0, sizeof(cap)); for(i=1; i<=M; i++) { scanf("%d", &room[i]); belong[i] = 0; } for(i=1; i<=N; i++) { scanf("%d", &num); for(j=1; j<=num; j++) { scanf("%d", &t); if(belong[t] == 0) { belong[t] = i; cap[S][i] += room[t]; } else cap[belong[t]][i] = INF; } scanf("%d", &t); cap[i][T] = t; } printf("%d/n", EK()); } return 0; }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值