zoukankan      html  css  js  c++  java
  • 网络流初识二(EK算法)

    EK算法是解决最大流问题常用的算法之一,复杂度优于FF算法。EK算法的思路和FF算法是一样的。不同之处是EK算法通过广搜寻路,FF算法深搜寻路。

    EK算法的具体步骤:

    首先是存图,可以采用邻接矩阵直接存,这种存图方式是比较简单的,后面更新残余网络也比较容易,但是空间复杂度比较高,不实用。

    另外一种存图方式是链式前向星存图。构造边的时候同时构造两个,正向边和逆向边。加入说正向边的编号为0,那么逆向边的编号为1,依次类推,即偶数为正向边,偶数+1为其对应的负向边。这样存的好处就是,如果我们知道了其中一边,比如说编号为3的这条边,那么它对应的正向边就是3^1=2,如果我们知道了2这条边,那么它对应的反向边就是2^1。

    然后是EK算法的核心就是通过BFS寻找一条从原点s到汇点t的一条增广路径。同时用数组dis[]护寻找到当前点的流量。当到达汇点t时,那么这条增广路径的流量dis[t]。

    然后更新残留网络,对刚才从s到t所经过的路径的边权进行流量更新,所以这就要求我们应该记录上一步搜索所走过的路径。

    最后叠加流量直到找不到增广路径为止。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    ll n,m,s,t;
    const ll N=1e5+7;
    const ll INF=1e18+7;
    struct stu{
        ll to,val,nxt;
    }edge[N];
    ll tol=0,head[N];
    ll flag[200+7][200+7];
    void add(ll x,ll y,ll z){
        edge[tol].to=y;
        edge[tol].val=z;
        edge[tol].nxt=head[x];
        head[x]=tol++;
    }
    ll dis[N];
    ll p[N];//记录每个节点的编号。,并不是其父节点。,因为其父节点就是当前节点对应的反向边 的另一个端点。 
    ll ans=0;
    bool mark[N];
    bool EK(ll s,ll t){
        memset(mark,0,sizeof mark);
        queue<ll>que;
        que.push(s);
        mark[s]=1;
        dis[s]=INF;
        while(que.size()){
            ll u=que.front();
            que.pop();
            for(ll i=head[u];i!=-1;i=edge[i].nxt){
                ll v=edge[i].to;
                if(mark[v])continue ;
                if(edge[i].val==0) continue ;
                mark[v]=1;
                p[v]=i;
                que.push(v);
                dis[v]=min(dis[u],edge[i].val); 
                if(v==t) return 1;
            }
        }
        return 0;
    }
    
    
    void update(){
        ll x=t;
        while(x!=s){
            ll v=p[x];
            edge[v].val-=dis[t];
            edge[v^1].val+=dis[t];
            x=edge[v^1].to;
        }
        ans+=dis[t];
    }
    int main(){
        cin>>n>>m>>s>>t;
        ll x,y,z;
        memset(head,-1,sizeof head); 
        for(ll i=0;i<m;i++){
            scanf("%lld%lld%lld",&x,&y,&z);
            if(flag[x][y]==0){//处理重边 
                add(x,y,z);
                flag[x][y]=tol;
                add(y,x,0);
            }
            else edge[flag[x][y]-1].val+=z;
        }
        while(EK(s,t)){
            update();
        }
        printf("%lld
    ",ans);
        return 0;
    } 

      

  • 相关阅读:
    Python 两个list合并成一个字典
    python 取列表(数组)偶数和奇数位置的值
    爬虫-Xpath语法笔记-转载
    详解Python requests 超时和重试的方法-转载
    6种负载均衡算法-转载
    python学习点滴记录-Day22
    python学习点滴记录-Day21-项目
    python学习点滴记录-Day20(分页、cookie/session、ajax)
    vimrc
    使用 find 命令实现高级排除需求
  • 原文地址:https://www.cnblogs.com/Accepting/p/13331512.html
Copyright © 2011-2022 走看看