• 最小费用最大流——EK+SPFA


    终于把最小费用最大流学会了啊……
    各种奇奇怪怪的解释我已经看多了,但在某些大佬的指点下,我终于会了。
    原来是个好水的东西。

    最小费用最大流是什么?

    不可能不知道网络流吧?如果不知道,自行百度去……
    费用流就是在每条边添加个费用,设你这条边的流量是f,费用为w,则总费用为fw
    举个例子,就像是有许多点的一张图,有很多个管子相连,每个管子都有个容量,并且每流一流量就要花一些费用,问总费用最少是多少。


    最小费用最大流怎么做?

    首先要知道EK算法……
    开玩笑的,其实根本不用,我还没打过普通的EK呢,就只是打过dinic和sap。
    这个做法其实很简单:
    1、用spfa从原点跑最短路,边权为费用(满流的边不用跑)。
    2、将最短路径抽出,在上面找一个残余容量最小的。
    3、这一路上的残余容量减少,反向弧的容量增加(反向弧的费用为负的正向的费用)。
    4、回到第一步,继续做下去,直到从原点跑不到汇点。
    这样就可以算出来了,这就是最普通的EK+spfa做法。
    当然还有更好的,但我还不会……
    时间复杂度我不知道,毕竟,网络流的时间总是很玄学啊……


    代码

    using namespace std;
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    int n,m,S,T;
    struct EDGE
    {
        int to,c,w;
        EDGE *las;
    } e[100001];
    int ne;
    EDGE *last[5001];
    #define rev(ei) (e+(int((ei)-e)^1))
    int q[1000001];
    bool inq[5001];
    bool SPFA();
    int dis[5001];
    EDGE *pre[5001];
    void flow(int&,int&);
    int main()
    {
        scanf("%d%d%d%d",&n,&m,&S,&T);
        for (int i=1;i<=m;++i)
        {
            int u,v,c,w;
            scanf("%d%d%d%d",&u,&v,&c,&w);
            e[ne]={v,c,w,last[u]};
            last[u]=e+ne;
            ++ne;
            e[ne]={u,0,-w,last[v]};
            last[v]=e+ne;
            ++ne;
        }
        int maxflow,mincost;
        flow(maxflow,mincost);
        printf("%d %d
    ",maxflow,mincost);
        return 0;
    }
    bool SPFA()
    {
        int h=-1,t=0;
        memset(dis,127,sizeof dis);
        dis[S]=0;
        pre[S]=NULL;
        q[0]=S;
        inq[S]=1;
        do
        {
            ++h;
            for (EDGE *ei=last[q[h]];ei;ei=ei->las)
                if (ei->c && dis[q[h]]+ei->w<dis[ei->to])
                {
                    dis[ei->to]=dis[q[h]]+ei->w;
                    pre[ei->to]=ei;
                    if (!inq[ei->to])
                    {
                        inq[ei->to]=1;
                        q[++t]=ei->to;
                    }
                }
            inq[q[h]]=0;
        }
        while (h!=t);
        return dis[T]!=0x7f7f7f7f;
    }
    void flow(int &maxflow,int &mincost)
    {
        maxflow=0;
        mincost=0;
        while (SPFA())
        {
            int minc=0x7f7f7f7f;
            for (EDGE *ei=pre[T];ei;ei=pre[rev(ei)->to])
                minc=min(minc,ei->c);
            maxflow+=minc;
            mincost+=dis[T]*minc;
            for (EDGE *ei=pre[T];ei;ei=pre[rev(ei)->to])
            {
                ei->c-=minc;
                rev(ei)->c+=minc;
            }
        }
    }

    这个代码我没有对过任何的标程,相信各位可以凭借自己的理解打出来,解析就不打了。

  • 相关阅读:
    webpack 打包性能分析工具
    npm 使用
    npm 构建时,次要版本变化引起的问题
    AtomicStampedReference、AtomicMarkableReference 区别
    vue-cli 中的静态资源处理
    vue-cli 构建项目中 config/index.js 文件解读
    webpack的3个路径配置项: assetsRoot、assetsSubDirectory、assetsPublicPath
    Vue2 dist 目录下各个文件的区别
    DllPlugin、DllReferencePlugin 可以提取的第三方库列表
    JUC集合之 CopyOnWriteArrayList
  • 原文地址:https://www.cnblogs.com/jz-597/p/11145286.html
Copyright © 2020-2023  润新知