网络最大流问题算法 —— Dinic 算法 && poj 1237

Dinic 算法:


由于BFS寻找终点太慢,但是DFS又不能保证找到最短路径,当然,如果中和一下,构造分层网络的方法就可以找到比较快的最短增广路,(阻塞流算法)
dinic与EK的区别之处在于,EK是用BFS去找增广路,而dinic是在层次图里用DFS找增广路。

基本思路:
        1.根据残量网络计算层次图;
        2.在层次图中使用DFS进行增广直到不存在增广路;
        3.不断重复直到无法增广的时候,算法结束。

所谓的层次图,在残量网络中从源点S起始进行BFS,这样每个顶点在BFS树中就会得到一个距源点s的距离d , 如果d(s) = 0,直接从s出发可以到达的点距离为1,下一层距离为2,,,,把具有相同距离的顶点放在同一层,在层次图中,只保留d(i) + 1 = d(j) 的边,这样在层次图中的任意路径就成为到达次顶点的最短路径。
在Dinic算法中,BFS的作用就是判断找的汇点是否在源点开始的层次图中。

接下来的问题是 如何在层次图中使用DFS进行增广?

如果找到一个节点在层次图中,用它往下延伸,一直延伸到汇点,如果存在,就在这条路上找最小容量,增广之;如果增广之后,

如果增广后,容量满了,阻塞之,实现方法即把这个点在层次图里的编号赋为其它点到不了的值,比如INT_MAX,-1。

如果不能到达汇点,这个节点返回上一层,继续找。

如果这个点都找完后(即上一层到达源点),再BFS从源点建立新的层次图,继续找。。。直到汇点不在新的层次图里结束。


 

#include <cstdio>
#include <queue>
#include <cstring>
#include <cstdlib>
#include <iostream>
using namespace std;
#define inf 0x3f3f3f3f

int tab[250][250];//邻接矩阵
int dis[250];//距源点距离,分层图
int N,M,ANS;//N:点数;M,边数

queue<int> Q;
int BFS()
{
     int u,v;
     memset(dis,-1,sizeof(dis));//以-1填充
     dis[1]=0;
     Q.push(1);
     while(!Q.empty()){
        u=Q.front(); Q.pop();
        for(v = 1;v <= N;v ++)
        if(tab[u][v] && dis[v] == -1){
            dis[v] = dis[u] + 1;
            Q.push(v);
        }
     }
     return dis[N]>0; //汇点的DIS小于零,表明BFS不到汇点
}

//Find代表一次增广,函数返回本次增广的流量,返回0表示无法增广
int find(int x,int low)//Low是源点到现在最窄的(剩余流量最小)的边的剩余流量
{
    int i,a=0;
    if (x==N)return low;//是汇点
    for (i=1;i<=N;i++)
    if (tab[x][i] >0 //联通
     && dis[i]==dis[x]+1 //是分层图的下一层
     &&(a=find(i,min(low,tab[x][i]))))//能到汇点(a <> 0)
    {
       tab[x][i]-=a;
       tab[i][x]+=a;
       return a;
    }
    return 0;

}
int main()
{
    int i,j,f,t,flow,tans;
    while (scanf("%d%d",&M,&N)!=EOF){
        memset(tab,0,sizeof(tab));
        for (i=1;i<=M;i++)
        {
            scanf("%d%d%d",&f,&t,&flow);
            tab[f][t]+=flow;
        }

        ANS=0;
        while (BFS())//要不停地建立分层图,如果BFS不到汇点才结束
        {
              while(tans=find(1,inf))
                ANS+=tans;//一次BFS要不停地找增广路,直到找不到为止
        }
        printf("%d\n",ANS);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值