【网络流】【模板】luogu P3376 网络最大流

L i n k Link Link

L u o g u Luogu Luogu P 3376 P3376 P3376

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 Sample Sample I n p u t Input Input

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 Sample Sample O u t p u t Output Output

50

H i n t Hint Hint

时空限制:1000ms,128M

数据规模:

对于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。

T r a i n Train Train o f of of T h o u g h t Thought Thought

D i n i c Dinic Dinic算法,每次用 b f s bfs bfs求出增广路,然后用 d f s dfs dfs增广就好了

增广路:

C o d e Code Code

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>

using namespace std;

const int inf = 1e9;
int t, n, m, s, tt, ans;
int dis[10005], h[200005];

struct node
{
	int y, w, op, next;
}g[200005];

void add(int x, int y, int w)
{
	g[++tt] = (node){y, w, tt + 1, h[x]}; h[x] = tt;//连正向边
	g[++tt] = (node){x, 0, tt - 1, h[y]}; h[y] = tt;//连反向边 
}

bool bfs()
{
	queue<int>Q;
	for (int i = 1; i <= n; ++i) dis[i] = inf;
	dis[s] = 0; Q.push(s);
	while (Q.size()) { 
		int x = Q.front(); Q.pop();
		for (int i = h[x]; i; i = g[i].next)
		{
			int y = g[i].y;
			if (dis[y] > dis[x] + 1 && g[i].w)
			{
				dis[y] = dis[x] + 1;//寻找增广路
				Q.push(y);
				if (y == t) return 1;
			}
		}
	} 
	return 0;
}

int dfs(int x, int maxf)
{
	if (x == t) return maxf;
	int ret = 0;//表示当前点的流量
	for (int i = h[x]; i; i = g[i].next)
	{
		int y = g[i].y;
		if (g[i].w && dis[y] == dis[x] + 1) {
			int xx = dfs(y, min(g[i].w, maxf - ret));//按照增广路增广
			if (!xx) dis[y] = -1;
			g[i].w -= xx; //正向边的残余流量减去当前流量
			g[g[i].op].w += xx;//反向边的可流量就加上这一流量
			ret += xx;//加入总流量
			if (ret == maxf) break;
		}
	}
	return ret;
}

int main()
{
	scanf("%d%d%d%d", &n, &m, &s, &t);
	for (int i = 1; i <= m; ++i)
	{
		int u, v, w;
		scanf("%d%d%d", &u, &v, &w);
		add(u, v, w);//连边
	} 
	while (bfs())
		ans += dfs(s, inf);
	printf("%d", ans);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值