最大流-dinic算法

dinic与EK算法的比较:

1、使用了层次网络,减小了寻找增广路的代价。

2、允许一次dfs多次增广,一次dfs可以把本层级网络的所有增广路都找出来。

学习EK算法请转到 最大流-EK(Edmond—Karp)算法


算法步骤:

(1)构建残余网络。

(2)构建层次网络。即初始化距离标号level。距离标号是指定点距离源点边数的最小值。

(3)dfs多路增广。这里找到一条增广路之后,一直回退直到一个顶点v扣除增广流量后还有残余流量,沿途更新边的 残余容量。注意到第一次返回到v时,v之前的边的容量并没有更新。直到从v点出发的所有增广路都找完了,才会向前返回并更新边的容量,这时更新值为从v点出发的所有增广路的总流量。相当于将流量积攒下来一起扣除。

(4)重复步骤(2)(3)。


第二次看自己写的博客,竟然没有看懂,于是就加深了一次对dinic的理解。

一直纠结于既然dinic可以一次dfs多次增广,为何还要多次建层次网络。后来画了一个图就明白了。


第一次建层次网络,T的距离标号为2,只能走S->1->T这条增广路。

第二次建层次网络时会将第一次获得的增广路的饱和边删去,于是就只能走S->2->3->4->T这条增广路,T的距离标号为4。

推荐一个大佬的博客:http://blog.csdn.net/wall_f/article/details/8207595#comments


题目链接:Drainage Ditches

自己整了一份比较简洁的模板

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<queue>
using namespace std;
#define inf 1<<29
int n,m;
int G[205][205];//残余网络
int level[205];//层级网络,各点的层级
int bfs(int s,int t)//构建层级网络
{
        memset(level,0,sizeof level);
        level[s]=1;
        queue<int> q;
        q.push(s);
        while(!q.empty())
        {
                int top=q.front(); q.pop();
                for(int i=1;i<=n;i++)
                if(!level[i] && G[top][i])//如果这个点没有被搜过,并且top->i这条边的残余容量大于0
                {
                        level[i]=level[top]+1;//将这个点的层级赋为上个点层级+1
                        q.push(i);//将这个点入队
                }
        }
        return level[t];//如果本层级网络能够到达终点
}
int dfs(int v,int t,int flow)//v为当前结点,t为终点,flow为v点存留的流量
{
        int s=flow,increase;//s记录源点的流量,也就是INF,increase为本条增广路的流量
        if(v==t) return flow;//如果搜到了终点,则返回flow,此时flow=increase
        for(int i=1;i<=n;i++)
        {
                if(G[v][i] && level[i]==level[v]+1)//如果v->i这条边残余容量>0,并且i为v的下一个层级
                {
                        increase=dfs(i,t,min(flow,G[v][i]));
                        G[v][i]-=increase;//更新残余网络
                        G[i][v]+=increase;
                        flow-=increase;//v点的残余容量减去增广消耗的流量
                }
        }
        return s-flow;//源点原容量(inf)-源点剩余容量(flow)=本层次网络增广的总流量
}
int dinic(int s,int t)
{
        int maxflow=0,f;
        while(bfs(s,t)) maxflow+=dfs(s,t,inf);//每次尝试构建层次网络,如果构建成功,maxflow加上本网络增广总流量
        return maxflow;
}
int main()
{
        while(~scanf("%d%d",&m,&n))
        {
                memset(G,0,sizeof G);
                int ui,vi,wi;
                for(int i=0;i<m;i++)
                {
                        scanf("%d%d%d",&ui,&vi,&wi);
                        G[ui][vi]+=wi;
                }
                printf("%d\n",dinic(1,n));
        }
        return 0;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值