zoukankan      html  css  js  c++  java
  • 让菜鸡讲一讲费用流(EK)

    让我再讲一个故事吧。

    又有一些小精灵要准备从银月城(S)迁徙到Nibel山(T)。

    这两个地方之间的道路构成了一个网络。

    每个道路都有它自己的容量,这决定了每天有多少小精灵可以同时从这儿通过。

    和上一篇不同的是,由于上次迁徙的规模很大,

    吸引了其它一些种族的注意,

    这次每条道路都会有一些人/兽人/哥布林/...向精灵们征收过路费,

    现在精灵们想知道,在花费最小的情况下,它们迁徙的速度最大是多少只每天。

    费用流=最小费用最大

    在要求流最大的情况下要求费用最小,好像原来的isap已经派不上用场了呢!

    让我们回到最朴实的EK算法上。

    EK算法每一次只寻找一条增广路,

    这带给它解决这一个方面的问题的得天独厚的优势。

    这是原来的EK算法:

    int BFS()
    {
        /*找到一条增广路*/
    }
    int ek()
    {
        /*对找到的增广路进行一系列处理*/
    }
    
    

    我们用BFS找增广路。

    想象一下,

    既然要求费用最小

    我们就把费用作为路径长度

    之后每一次跑一遍最短路

    那么就可以保证花费最小了!


    所以,我们只要把原来的BFS()改成spfa()或者dijkstra()就好啦

    ps.一般dijkstra只能跑不带负权边的图,
    但是有一种特殊的技巧可以把边权魔改成正的。
    

    以下是拿辣鸡spfa跑的费用流

    #include<bits/stdc++.h>
    using namespace std;
    typedef pair<int,int> pii;
    #define mp(a,b) make_pair(a,b)
    #define ll first
    #define rr second
    inline int gotcha()
    {
        register int a=0,b=1,c=getchar();
        while(!isdigit(c))b^=a=='-',c=getchar();
        while(isdigit(c))a=a*10+c-48,c=getchar();
        return b?a:-a;
    }
    const int _ = 5002 , __ = 50002<<1 , inf = 0x3f3f3f3f;
    int to[__],ne[__],v[__],co[__],he[__]={0},ecnt=1;
    int n,m,dis[_],pe[_],pv[_],S,T;
    bool ed[_];
    void adde(int a,int b,int c,int d){to[++ecnt]=b,v[ecnt]=c,co[ecnt]=d,ne[ecnt]=he[a],he[a]=ecnt;}
    queue<int> q;
    int spfa()
    {
        memset(dis,63,sizeof(dis)),memset(ed,0,sizeof(ed));
        while(!q.empty())q.pop();
        register int i,a;
        q.push(S),ed[S]=1,dis[S]=0;
        while(!q.empty())
        {
            a=q.front(),q.pop();ed[a]=0;
            for(i=he[a];i;i=ne[i])
                if(v[i]>0 && dis[to[i]]>dis[a]+co[i])
                {
                    dis[to[i]]=dis[a]+co[i];
                    pe[to[i]]=i,pv[to[i]]=a;
                    if(!ed[to[i]])ed[to[i]]=1,q.push(to[i]);
                }
        }
        return dis[T]<inf;
    }
    pii mfmc()
    {
        register int i,sco=0,sfl=0,flw;
        while(spfa())
        {
            flw=inf;
            for(i=T;i!=S;i=pv[i])flw=min(flw,v[pe[i]]);
            for(i=T;i!=S;i=pv[i])v[pe[i]]-=flw,v[pe[i]^1]+=flw;
            sco+=flw*dis[T],sfl+=flw;
        }
        return mp(sfl,sco);
    }
    int main()
    {
        register int i,j,k,a,b;
        register pii tmp;
        n=gotcha(),m=gotcha(),S=gotcha(),T=gotcha();
        for(i=1;i<=m;i++)
        {
            j=gotcha(),k=gotcha(),a=gotcha(),b=gotcha();
            adde(j,k,a,b),adde(k,j,0,-b);
        }
        tmp=mfmc();
        printf("%d %d",tmp.ll,tmp.rr);
        return 0;
    }
    

    这就不写伪代码了吧!?

    以后补

  • 相关阅读:
    Java实现热替换
    SQL判断字符串里不包含字母
    Useful bat command
    Entity FrameworkCore教程(一):包概念理解
    Docker:Docker常见命令
    ASP.NET Core:ASP.NET Core程序使用Docker部署
    ASP.NET Core:中间件
    ASP.NET Core:依赖注入
    Jenkins:创建定时构建任务
    ASP.NET Core 3.1使用Swagger
  • 原文地址:https://www.cnblogs.com/finder-iot/p/8409010.html
Copyright © 2011-2022 走看看