最大流三大算法——2,dinic算法

最大流背景介绍:比如城市水管,从水站运水送你家,许多管道总共能同时送多少水到

最大流分三个算法,算法难度与优越性逐步提升:

1,EK(Edmonds−Karp)算法

2,dinic算法

3,ISAP算法

1,算法特点

我们说过:EK算法每次都可能会遍历整个残量网络,但只找出一条增广路,这样是不是太浪费了,我们能否做到一次找多条增广路呢

dinic算法做得到,

我们bfs找增广路时对点之间建层(设起点层数1,0表示还未访问,没有建层),建层后我们可以用dfs去遍历每一层,这样就实现多路增广

可能你会发现,似乎还有改进的空间,先上图

 如果我们前面dfs把1->3后面的路径走了4,5两条(并让他不能再增广了),那我2号点往下走,难道还要去不能增广的路径吗,不应该直接去6号吗,所以我们可以开个now数组,标记now[x]指向后面哪个点了,如果更新到6,就指向6(不再是前面的4,5),这样就实现了当前弧优化

2,还是那个模板题:P3376 【模板】网络最大流

#include <bits/stdc++.h>
using namespace std;
#define ll     long long
const int INF = 0x3f3f3f3f;
const int N = 2e3 + 100;

int n, m, s, t;
ll head[N];
ll now[N];
ll num = 1;
ll dis[N];
ll ans;
struct node
{
	ll next, w, to;
} edge[N << 2];

void add(ll u, ll v, ll w)
{
	edge[++num].next = head[u];
	edge[num].w = w;
	edge[num].to = v;
	head[u] = num;

	edge[++num].next = head[v];
	edge[num].w = 0;
	edge[num].to = u;
	head[v] = num;
}

int bfs()
{
	memset(dis, 0, sizeof(dis));//这里的dis相当于ek算法dis与vis俩个数组的作用,表示层数,起点s为1层,0表示没有访问过
	dis[s] = 1;
	now[s] = head[s];//初始赋值起点层数,并且用now记录目前点的num值(head[])
	queue<int>q;
	q.push(s);
	while (!q.empty())
		{
			int x = q.front();
			q.pop();
			for (int i = head[x]; i; i = edge[i].next)
				{
					int v = edge[i].to;
					ll w = edge[i].w;
					if (dis[v] || !w)continue;//只有这个点没有访问过并且值不为0,我才进行下面操作
					dis[v] = dis[x] + 1;//首先层数加一
					now[v] = head[v];//用now记录,便于后面当前弧优化
				//注意,我们要找多条增广路,所以不是到终点就退出,而是走到完
					q.push(v);
				}
		}
	return dis[t]!=0;//如果终点有被赋予过层数,说明有增广路
}

ll dfs(int x, ll sum)//sum表示前面的流过来的水有多少
{
	if (x == t)return sum;//到终点了,等于走完所有增广路,此时sum剩余多少就全能去终点,不会被限制
	ll k, res = 0;//k是后面点最大流量
	for (int i = now[x]; i && sum; i = edge[i].next)//i = now[x]当前弧优化,从没被增广完的路径开始   //i&&sum,sum只有大于0才有往下的必要
		{
			now[x] = i;//x继承最新的点
			int v = edge[i].to;
			ll w = edge[i].w;
			if (dis[v] == dis[x] + 1 && w)//只有是层数间隔1并且还有可以增广的容量才可以进来
				{

					k = dfs(v, min(sum, w));//min(sum, w)表示这个点可以容纳的是最大容量(sum比他大),还是剩下的水流sum
                   if(!k)continue;
					edge[i].w -= k;
					edge[i ^ 1].w += k;
					res += k;//res表示当前x点增广的流量
					sum -= k;//总流量减少(被分流了)
				}
		}

	return res;
}

int main()
{
	cin >> n >> m >> s >> t;
	ll u, v, w;
	for (int i = 1; i <= m; ++i)
		{
			cin >> u >> v >> w;
			add(u, v, w);
			
		}
	ans = 0;
	while (bfs())
		{
			ans += dfs(s, INF);
		}
	cout << ans << endl;
	return 0;
}

3,评估

算法复杂度:O(n^2*m),n是点,明显比ex算法m边平方优越多了,但是我跑完一次dfs就要回去再建图,是不是还是麻烦呢

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值