【网络流算法模板】最大流:dinic模板

这里以poj1459为例,模板中运用了 当前弧优化 ,即如果某次搜索中发现某条边不能流通,就把这条边舍去,以免重复搜索浪费时间

对于分层图的解释:引自白书:“每次寻找最短增广路,因为最短增广路长度在增广过程中始终不会变短。我们可以先进行一次宽度优先搜索,然后考虑由近距离点指向远距离点组成分层图,在上面进行深搜寻找最短增广路。如果找不到新的增广路了,说明最短增广路的长度变长了,或者不存在增广路了,于是通过宽搜寻找构成新的分层图。每一步构造分层图复杂度O(E),每一步完成后至少增广路长度至少增加1,且增广路长度不会超过V-1则,最多O(V)步,这样就能保证复杂度小于等于O(E *V *V)”

若想要认真学习该算法,建议看这位dalao的文章:
https://www.cnblogs.com/SYCstudio/p/7260613.html

#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<queue>
#include<stdlib.h>
using namespace std;
int n,ns,nt,m,iter[105],dis[105];
int tot,head[105],nex[40005],to[40005],f[40005],ni[40005];
queue<int>q;
void add(int u,int v,int w)//建图加边,每次建图时,建一条反向弧,并记录某个弧的反向弧编号
{
    tot++;//建正向弧
    to[tot]=v;
    f[tot]=w;
    nex[tot]=head[u];
    head[u]=tot;

    tot++;//建反向弧
    to[tot]=u;
    f[tot]=0;
    nex[tot]=head[v];
    head[v]=tot;
    //互相记录编号
    ni[tot]=tot-1;
    ni[tot-1]=tot;
}
void bfs(int s)//bfs对图按照与源点的距离进行分层
{
    dis[s]=0;
    q.push(s);
    while(!q.empty())
    {

        int now=q.front();q.pop();
        for (int i=head[now];i!=0;i=nex[i])
        {
            int v=to[i];
            if (dis[v]==-1 && f[i]>0)
            {
                dis[v]=dis[now]+1;
                q.push(v);
            }
        }
    }
}
int dinic(int x,int t,int tf) //记录本次最多能流多大
{
    if (x==t) return tf;
    for (int i=iter[x];i!=0;i=nex[i])
    {
        iter[x]=i;//当前弧优化
        int v=to[i];
        if (dis[v]!=dis[x]+1 || f[i]==0) continue;//不流通的情况就continue
        int tmp=dinic(v,t,min(tf,f[i]));//如果可以从这条边拓展下去可以流通
        if (tmp>0)
        {
            f[i]-=tmp;
            f[ni[i]]+=tmp;
            return tmp;
        }
    }
    return 0;
}
int max_f(int s,int t)//求最大流
{
    int ans=0;
    while(1)
    {


        for (int i=0;i<=n+2;i++)//初始化
            iter[i]=head[i],dis[i]=-1;

        bfs(s);
        if (dis[t]==-1) break;//说明已经没有能到达终点的通路
        while(1)
        {
            int tmpf=dinic(s,t,9990000);
            if (tmpf<=0) break;
            ans+=tmpf;

        }
    }
    return ans;
}
char p1,p2,p3;
int main()
{
    while(scanf("%d%d%d%d",&n,&ns,&nt,&m)!=EOF)
    {
        tot=0;
        for (int i=0;i<=n+2;i++)
            head[i]=0;
        for (int i=1,x,y,z;i<=m;i++)
        {
            cin>>p1>>x>>p2>>y>>p3>>z;
            if (x==y) continue;
            add(x,y,z);
        }
        for (int i=1,x,y;i<=ns;i++)
        {
            cin>>p1>>x>>p2>>y;
            add(n+1,x,y);
        }
        for (int i=1,x,y;i<=nt;i++)
        {
            cin>>p1>>x>>p2>>y;
            add(x,n+2,y);
        }
        int ans=max_f(n+1,n+2);
        printf("%d\n",ans);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值