最大网络流模板Dinic算法

#include <iostream> 
#include <queue> 
#include <vector> 
#include <algorithm> 
#include <deque> 
using namespace std;
#define INFINITE 999999999 //Poj 1273 Drainage Ditches 的 Dinic算法
int G[300][300];
bool Visited[300];
int Layer[300]; int n,m; //1是源点,m是汇点
bool CountLayer() 
{
    int layer = 0; deque<int>q;
    memset(Layer,0xff,sizeof(Layer));//都初始化成-1
    Layer[1] = 0; q.push_back(1);
    while( ! q.empty())
    {
        int v = q.front();
        q.pop_front();
        for( int j = 1; j <= m; j ++ ) 
        {
            if( G[v][j] > 0 && Layer[j] == -1 ) 
            {
                //Layer[j] == -1 说明j还没有访问过
                Layer[j] = Layer[v] + 1;
                if( j == m ) //分层到汇点即可
                    return true;
                else
                    q.push_back(j);
            }
        }
    }
    return false;
}
int Dinic()
{
    int i; int s;
    int nMaxFlow = 0;
    deque<int> q;//DFS用的栈
    while( CountLayer() )
    { //只要能分层
        q.push_back(1); //源点入栈 
        memset(Visited,0,sizeof(Visited)); Visited[1] = 1;
        while( !q.empty())
        {
            int nd = q.back();
            if( nd == m ) 
            {   // nd是汇点
                //在栈中找容量最小边
                int nMinC = INFINITE;
                int nMinC_vs; //容量最小边的起点
                for( i = 1;i < q.size(); i ++ ) 
                {
                    int vs = q[i-1];
                    int ve = q[i];
                    if( G[vs][ve] > 0 ) 
                    {
                        if( nMinC > G[vs][ve] ) 
                        {
                            nMinC = G[vs][ve];
                            nMinC_vs = vs;
                        }
                    }
                }
                //增广,改图
                nMaxFlow += nMinC;
                for( i = 1;i < q.size(); i ++ ) 
                {
                    int vs = q[i-1];
                    int ve = q[i];
                    G[vs][ve] -= nMinC; //修改边容量
                    G[ve][vs] += nMinC; //添加反向边
                }
                //退栈到 nMinC_vs成为栈顶,以便继续dfs
                while( !q.empty() && q.back() != nMinC_vs )
                {
                    Visited[q.back()] = 0; //没有这个应该也对
                    q.pop_back();
                }
            }
            else
            {   //nd不是汇点
                for( i = 1;i <= m; i ++ )
                {
                    if( G[nd][i] > 0 && Layer[i] == Layer[nd] + 1 &&
                    ! Visited[i])
                    {
                        //只往下一层的没有走过的节点走
                        Visited[i] = 1;
                        q.push_back(i);
                        break;
                    }
                }
                if( i > m) //找不到下一个点
                    q.pop_back(); //回溯
            }
        }
    }
    return nMaxFlow;
}
int main()
{
    while (cin >> n >> m )
    {
        int i,j,k;
        int s,e,c;
        memset( G,0,sizeof(G));
        for( i = 0;i < n;i ++ ) 
        {
            cin >> s >> e >> c;
            G[s][e] += c; //两点之间可能有多条边
        }
        cout << Dinic() << endl;
    }
    return 0;
}

模板来自
网络流算法
北京大学信息学院 郭炜

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值