最大网络流 EK 算法

          网络流是什么类型的问题,看一道题目你就知道了 点击打开链接 。

默认具备图论的基本知识,网络流概念比较多,先看看书熟悉一下那些概念。比较好!一个寄出的网络最大流。EK算法写的。


 这是一幅网络,求S  ------>  T   点的最大网络流。  这是初始状态。{a,b}  a 代表该边的最大流量,b代表实际的流量。

一开始,实际流量为0;下面是代码。


<pre name="code" class="cpp">#include <cstdio>
#include <cstring>
#include <cctype>
#include <cmath>
#include <set>
#include <map>
#include <list>
#include <queue>
#include <deque>
#include <stack>
#include <string>
#include <bitset>
#include <vector>
#include <iostream>
#include <algorithm>
#include <stdlib.h>

using namespace std;
typedef long long LL;
const int INF=2e9+1e8;
const int MOD=1e9+7;
const int MM=250;
const double eps=0.0000000001;

struct Node
{
    int c,f;
};
Node edge[MM][MM];
int n,m,pre[MM];

bool bfs(int s,int t)
{
    bool vis[MM];
    memset(vis,0,sizeof(vis));
    memset(pre,-1,sizeof(pre));
    queue<int>q;
    q.push(s);
    vis[s]=true;
    while(!q.empty())
    {
        s=q.front();
        q.pop();
        for(int i=1; i<=m; i++)
        {
            if(!vis[i]&&edge[s][i].c>abs(edge[s][i].f))
            {
                vis[i]=true;
                pre[i]=s;
                if(i==t) return true;
                q.push(i);
            }
        }
    }
    return false;
}
void print(stack<int>& a)//打印路径
{
    cout<<"1";
    while(!a.empty())
    {
        cout<<"->"<<a.top();
        a.pop();
    }
    cout<<endl;
}
int solve()
{
    int maxflow=0;
    while(true)
    {
        if(!bfs(1,m)) return maxflow;
        int flow=INF;
        stack<int>s;
        for(int x=m,y=pre[m]; y!=-1; x=y,y=pre[y])
        {
            flow=min(flow,edge[y][x].c-edge[y][x].f);
            s.push(x);
        }
        //  print(s);
        for(int x=m,y=pre[m]; y!=-1; x=y,y=pre[y])
        {
            edge[y][x].f+=flow;
            edge[x][y].f-=flow;
        }
        maxflow+=flow;
    }
}
int main()
{
    while(cin>>n>>m)
    {
        memset(edge,0,sizeof(edge));
        for(int i=0; i<n; i++)
        {
            int s,t,val;
            cin>>s>>t>>val;
            edge[s][t].c+=val;
        }
        printf("%d
",solve());
    }
    return 0;
}


/*
                   _ooOoo_
                  o8888888o
                  88" . "88
                  (| -_- |)
                  O  =  /O
               ____/`---'\____
             .'  \|     |//  `.
            /  \|||  :  |||//  
           /  _||||| -:- |||||-  
           |   | \  -  /// |   |
           | \_|  ''---/''  |   |
             .-\__  `-`  ___/-. /
         ___`. .'  /--.--  `. . __
      ."" '<  `.___\_<|>_/___.'  >'"".
     | | :  `- \`.;` _ /`;.`/ - ` : | |
        `-.   \_ __ /__ _/   .-` /  /
======`-.____`-.___\_____/___.-`____.-'======
                   `=---='
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
         The program have no BUG.
*/



 

该算法的大致思路是:不断的找寻s到t的可行流。直到找不到为止。每次找到都要之后改变该路径上的实际流量。

用广搜来寻找路径。


比如第一次找到的路径是    S   → 1  →2 →T;增加流量为4

把实际流量更新后得到


再找 S→1→4→T

这条路上S到1只剩下1 所以增加的流量为1 便得到


再找 S→3→4→1

可以增加的流量为 4  ,便得到



下一次将不会找到再可以增加流量的路径。所以程序结束,增加流量为     4+1+4;所以最大流为9;


不过还有一种情况:


从肉眼来看很容易 S→1→2→T     加      S→3→4→T  得到15;


但是计算机执行有可能会首选 S→1→4→T。便得到  再选择  S→1→2→T得到右图

          

就再搜不到其他的了但是得到的确实10;说明这样作并不是最优的。所以EK算法提供了一种后悔的机制。正向流量加的同时,反向容量也同时加。这样就相当于   让刚刚流经1到4的让他从1→2→T 我从 4→T

  

1与4 这条边,一开始是从1到4流过5,反方的流量就变为5;当另一个流经  S,3,4 时  就可以走1,2,T 。合起来就是

S→3→4→1→2→T  又增加流量为5 到最后  E<1,4> 这条边总流量为 0;这种机制刚好解决了这个问题。

OVER




原文地址:https://www.cnblogs.com/coded-ream/p/7207973.html