【模板】Dinic求网络最大流

本文介绍了一种高效的网络最大流算法——Dinic算法。该算法通过构建层次图来减少寻找增广路的成本,并利用DFS进行增广操作。文章还介绍了如何通过当前弧优化进一步提升效率。
Dinic算法思路
  1. 根据残量网络计算层次图
  2. 在层次图中使用DFS进行增广直到不存在增广路
  3. 重复以上步骤直到无法增广

首先对每条弧存一条反向弧,初始流量为0,当正向弧剩余流量减少时,反向弧剩余流量随之增加,这样就为每条弧提供了一个反悔的机会,可以让一个流沿反向弧退回而去寻找更优的路线。对于一个网络流图,用bfs将图分层,只保留每个点到下一个层次的弧,目的是减少寻找增广路的代价。对于每一次可行的增广操作,用dfs的方法寻找一条由源点到汇点的路径并获得这条路径的流量c。根据这条路径修改整个图,将所经之处正向边流量减少c,反向边流量增加c。如此反复直到bfs找不到可行的增广路线。

当前弧优化

对于一个节点x,当它在dfs中走到了第i条弧时,前i-1条弧到汇点的流一定已经被流满而没有可行的路线了。那么当下一次再访问x节点的时候,前i-1条弧就可以被删掉而没有任何意义了。所以我们可以在每次枚举节点x所连的弧时,改变枚举的起点,这样就可以删除起点以前的所有弧以达到优化的效果。

【模板】网络最大流 洛谷P3376
#include<bits/stdc++.h>
#define INF 10000000
using namespace std;
int head[10005],nex[200005],tail[200005],cap[200005],tp=-1,dep[10005];
int fir[10005];
int n,m,s,t,a,b,v;
int dfs(int x,int now)
{
    if(!now || x==t)    return now;
    int c=0;
    for(int &i=fir[x];i!=-1;i=nex[i])
    {
        if(cap[i] && dep[tail[i]]==dep[x]+1)
        {
            int f=dfs(tail[i],min(now,cap[i]));
            c+=f;
            now-=f;
            cap[i]-=f;
            cap[i^1]+=f;
            if(!now)        break;
        }
    }
    return c;
}
inline bool bfs()
{
    memset(dep,0,sizeof(dep));
    dep[s]=1;
    queue<int>q;
    q.push(s);
    while(!q.empty())
    {
        int x=q.front();
        q.pop();
        for(int i=head[x];i!=-1;i=nex[i])
        {
            if(cap[i]&&!dep[tail[i]])
            {
                dep[tail[i]]=dep[x]+1;
                q.push(tail[i]);
            }
        }
    }
    return dep[t];
}
void add(int x,int y,int v)
{
    nex[++tp]=head[x];
    head[x]=tp;
    tail[tp]=y;
    cap[tp]=v;
}
inline int Dinic()
{
    int c=0;
    while(bfs())
    {
        for(int i=1;i<=n;++i)        fir[i]=head[i];
        c+=dfs(s,INF);
    }    
    return c;
}
int main()
{
    memset(head,-1,sizeof(head));
    scanf("%d%d%d%d",&n,&m,&s,&t);
    for(int i=1;i<=m;++i)
    {
        scanf("%d%d%d",&a,&b,&v);
        add(a,b,v);
        add(b,a,0);
    }
    printf("%d",Dinic());
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zP1nG

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值