【模板】最大网络流

D e s c r i p t i o n Description Description

如题,给出一个网络图,以及其源点和汇点,求出其网络最大流。

I n p u t Input Input

第一行包含四个正整数N、M、S、T,分别表示点的个数、有向边的个数、源点序号、汇点序号。

接下来M行每行包含三个正整数ui、vi、wi,表示第i条有向边从ui出发,到达vi,边权为wi(即该边最大流量为wi)

O u t p u t Output Output

一行,包含一个正整数,即为该网络的最大流。

S a m p l e I n p u t Sample Input SampleInput
4 5 4 3
4 2 30
4 3 20
2 3 20
2 1 30
1 3 40
S a m p l e O u t p u t Sample Output SampleOutput
50

H i n t Hint Hint

对于30%的数据:N<=10,M<=25

对于70%的数据:N<=200,M<=1000

对于100%的数据:N<=10000,M<=100000

样例说明:
在这里插入图片描述

题目中存在3条路径:

4–>2–>3,该路线可通过20的流量

4–>3,可通过20的流量

4–>2–>1–>3,可通过10的流量(边4–>2之前已经耗费了20的流量)

故流量总计20+20+10=50。输出50。

思路

最大网络流
每次用bfs求一次增广路
然后用dfs在每一个管道上更新

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
#define INF 1e9
using namespace std;
struct whw
{
	int w, h, op,  flow;
}wh[200005];
//w:这个管道连接的另一点
//h:此点连接的下一个管道
//op:此管道的反向管道
//flow:此管道的最大流量
int Ans, start, end, n, m, x, y, z, t;
int h[200005], F[10005], dis[10005];
void hw(int x, int y, int z)//建边
{wh[++t] = (whw){y, h[x], t + 1, z}, h[x] = t;
wh[++t] = (whw){x, h[y], t - 1, 0}, h[y] = t;}//反向边
//因为一开始没有水流过此管道,所以反向管道的可流量为0
bool Bfs()
{
	queue<int>s;
	for(int i  = 1; i <= n; ++i)F[i] = INF;//编号
	F[start] = 0;
	s.push(start);
	while(s.size())
	{
		int xy = s.front();s.pop();
		for(int i = h[xy]; i; i = wh[i].h)
			if(F[wh[i].w] > F[xy] + 1 && wh[i].flow)
			{
				F[wh[i].w] = F[xy] + 1;
				if(wh[i].w == end)return 1;//若到达终点
				s.push(wh[i].w);
			}
	}
	return 0;
}
int Dfs(int k, int maxf)//maxf为此点可以流的最大流量
{
	if(k == end)return maxf;//如到终点,则返回此管道最大的流量
	int flow = 0; //k点的实际最大流出量
	for(int i = h[k]; i; i = wh[i].h)
		if(wh[i].flow && F[k] + 1 == F[wh[i].w])//只流编号+1的和还可以流的管道
		{
			int now = Dfs(wh[i].w, min(maxf - flow, wh[i].flow));//下一个支点可以流的流量
			if(!now) dis[wh[i].w] = -1;//如果此点无法流,标记一下,以后就不走这了
			wh[i].flow -= now;//正向边的剩余流量
			wh[wh[i].op].flow += now;//反向边的可流量
			flow += now;
			if(flow == maxf)break;//如果已经到达最大可流量
		}
	return flow;
}
int main()
{
	scanf("%d%d", &n, &m);
	scanf("%d%d", &start, &end);
	for(int i = 1; i <= m; ++i)
	{
		scanf("%d%d%d", &x, &y, &z);
		hw(x, y, z);
	}
	while(Bfs())Ans += Dfs(start, INF);
	printf("%d" , Ans);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值