网络流略解 网络流 24 题索引

网络流

网络流 (network-flows) 是一种类比水流的解决问题方法,与线性规划密切相关。图论中的一种理论与方法,研究网络上的一类最优化问题。在这里插入图片描述
网络流的图可以抽象成以下模型。

对于一张边权图,每条边的权值指流量。流量 是指允许通过该边的最大权,而可以有不限多的权同时停留在一点上。

特别地,一图中存在两特殊点:源点和汇点。
源点 指初状态拥有无穷多权的点。一般题目不提供这个点(告诉你就等于告诉你是网络流了),它是一个虚点。
汇点 指出度为 0 0 0 的、用于记录答案的虚点。
如上图所示, S T ST ST 是源点, E D ED ED 是汇点。

求从源点通过边走到汇点的权的最大值。这就是 最大流 问题。你可以把它想象成:有一些水管,它们有一定的耐久度,流过一定量的水后就会断裂失效。从一个有无穷多水的点开始流,最多有多少水流到汇点。

使用 Dinic 算法求最大流步骤如下。

  1. 把源点视为第一层,尝试遍历所有点并求出深度;
  2. 尝试 从浅到深 的顺序 从源点开始 流;
  3. 重复 1. 2. 操作。若无法搜到汇点,结束算法。

例题

求下图的最大流。
在这里插入图片描述其中 inf ⁡ \inf inf 表示无穷大。

我们首先从 S T ST ST 分别流 inf ⁡ \inf inf 1 , 2 , 3 1,2,3 1,2,3。尝试 1 → 5 , 6 ;   5 , 6 → E D 1\to5,6;\ 5,6\to ED 15,6; 5,6ED,对答案贡献为 2 2 2 2 → 5 , t → E D , a n s + 5 2\to5,t\to ED,ans+5 25,tED,ans+5 3 → 4 , 4 → E D , a n s + 1 3\to4,4\to ED,ans+1 34,4ED,ans+1
所以最大流为 2 + 5 + 1 = 8 2+5+1=8 2+5+1=8

当题目描述与“流水”无关时,尝试将题目转换成流水模型。


luogu P2740 [USACO4.2]草地排水Drainage Ditches 农夫约翰知道每一条排水沟每分钟可以流过的水量,和排水系统的准确布局(起点为水潭而终点为小溪的一张网)。需要注意的是,有些时候从一处到另一处不只有一条排水沟。

根据这些信息,计算从水潭排水到小溪的最大流量。对于给出的每条排水沟,雨水只能沿着一个方向流动,注意可能会出现雨水环形流动的情形。


参考代码

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;

const int MAXN=210;
const int inf=0x3f3f3f3f;

struct edge{
	int x,y,d,next,other;
}e[MAXN+MAXN];
int len=0;
int first[MAXN];
int n,m;
int sx,sy,sd;
int f[MAXN],q[MAXN],h[MAXN];
int st,ed;

void ins(int x,int y,int d){
	e[++len].x=x;e[len].y=y;e[len].d=d;
	e[len].next=first[x];first[x]=len;
	e[++len].x=y;e[len].y=x;e[len].d=0;
	e[len].next=first[y];first[y]=len;
	e[len].other=len-1;
	e[len-1].other=len;
}
int bfs(){
	memset(h,0,sizeof(h));h[1]=1;
	st=1;ed=2;q[1]=1;
	while(st!=ed){
		int x=q[st];
		for(int i=first[x];i;i=e[i].next){
			int y=e[i].y;
			if(!h[y]&&e[i].d>0){
				h[y]=h[x]+1;
				q[ed++]=y;
			}
		}
		++st;
	}
	return bool(h[n]>0);
}
int dfs(int x,int f){
	if(x==n) return f;
	int tt=0;
	for(int i=first[x];i;i=e[i].next){
		int y=e[i].y;
		if(h[y]==h[x]+1&&e[i].d>0&&f>=tt){
			int flow=dfs(y,min(f-tt,e[i].d));
			tt+=flow;
			e[i].d-=flow;
			e[e[i].other].d+=flow;
		}
	}
	if(!tt) h[x]=0;
	return tt;
}
inline int read(){
	int x=0; char c;
	do c=getchar(); while(c<'0'||c>'9');
	while(c>='0'&&c<='9')
		x=x*10+c-48,c=getchar();
	return x;
}
int main(){
	m=read();n=read();
	memset(first,0,sizeof(first));
	for(int i=1;i<=m;++i){
		sx=read();sy=read();sd=read();
		ins(sx,sy,sd);
	}
	int ans=0;
	while(bfs())
		ans+=dfs(1,inf);
	printf("%d",ans);
}

网络流 24 题索引

此表按笔者解决的时间顺序排列,一定程度上反映了难度情况。可供参考。

序号题目题解
1 1 1P2756 飞行员配对方案问题已解决
2 2 2P4016 负载平衡问题已解决
3 3 3P2763 试题库问题已解决
4 4 4P2761 软件补丁问题未解决
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值