zoukankan      html  css  js  c++  java
  • 最大网络流 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




  • 相关阅读:
    性能优化随笔
    Linux文件类型及如何查看,修改文件读写权限
    ngx_pagespeed
    用U盘安装Linux系统的简单方法
    Maven 3 入门 安装与配置
    CentOS 6.2 安装教程
    各种代码文件中的注释格式
    Linux下的WebLogic安装部署
    Win8常用快捷键
    Jenkins入门总结
  • 原文地址:https://www.cnblogs.com/coded-ream/p/7207973.html
Copyright © 2011-2022 走看看