zoukankan      html  css  js  c++  java
  • Luogu P3381 (模板题) 最小费用最大流

    <题目链接>

    题目大意:

    给定一张图,给定条边的容量和单位流量费用,并且给定源点和汇点。问你从源点到汇点的最带流和在流量最大的情况下的最小费用。

    解题分析:

    最小费用最大流果题。 

    下面的是MCMF的模板。想学ZKW费用流最小费用流的原始对偶 (Primal-Dual) 算法的同学,可以看看ZKW本人(Orz)的讲解  >>>

    #include <bits/stdc++.h>
    using namespace std;
    int h[5210],d[5210],used[5210],que[100010],last[5210];
    int cnt=1,INF=0x3f3f3f3f,ans1=0,ans2=0;
    #define clr(a,b) memset(a,b,sizeof(a))
    template<typename T>
    inline void read(T&x){
        x=0;int f=1;char c=getchar();
        while(c<'0' || c>'9'){ if(c=='-')f=-1;c=getchar(); }
        while(c>='0' && c<='9'){ x=x*10+c-'0';c=getchar(); }
        x*=f;
    }
    struct Edge{ int to,cap,cost,next; }e[120010];
    
    inline void add(int from,int to,int c1,int c2){
        e[++cnt]=(Edge){to,c1,c2,h[from]};h[from]=cnt;
        e[++cnt]=(Edge){from,0,-c2,h[to]};h[to]=cnt;
    }
    bool spfa(int s,int t){            //slf优化
        clr(last,0);clr(d,INF);clr(used,0);
        int head,tail;
        tail=head=50002;
        que[tail]=s;used[s]=1;d[s]=0;     
        while(head<=tail){        //数组模拟双端队列   
            int x=que[head++];
            for(int i=h[x];i;i=e[i].next){
                if(e[i].cap&&d[x]+e[i].cost<d[e[i].to]){      //如果这条路上还有残余容量,就更新其费用,让其费用最小
                    d[e[i].to]=d[x]+e[i].cost;
                    last[e[i].to]=i;      //记录这个点的最大费用所对应的前一条边的编号
                    if(!used[e[i].to]){    
                        if(d[e[i].to]<d[que[head]])que[--head]=e[i].to;    //如果这个点的费用小于队列的头部的话,就将它塞入队列头部
                        else que[++tail]=e[i].to;     //否则的话,塞入队尾
                        used[e[i].to]=1;
                    }
                }
            }
            used[x]=0;
        }
        return d[t]!=INF;   
    }
    void MCMF(int t){
        int minn=INF;
        for(int i=last[t];i;i=last[e[i^1].to])minn=min(minn,e[i].cap);      //沿着那个记录的反向增广路径更新这条路上的最小容量
        ans1+=minn;   
        for(int i=last[t];i;i=last[e[i^1].to]){
            ans2+=e[i].cost*minn;     //费用=单位流量费用*流量
            e[i].cap-=minn;     //正向边容量-=minn
            e[i^1].cap+=minn;   //反向边容量+=minn
        }
    }
    int main(){
        int n,m,s,t;
        read(n);read(m);read(s);read(t);
        for(int i=1;i<=m;i++){     
            int x,y,w,f;read(x);read(y);read(w);read(f);
            add(x,y,w,f);  
        }
        while(spfa(s,t))MCMF(t);
        printf("%d %d
    ",ans1,ans2);
    }
  • 相关阅读:
    04 16 团队竞技(第二场) 赛后总结
    HDU 1863 畅通工程 克鲁斯卡尔算法
    HUD 2544 最短路 迪杰斯特拉算法
    hdoj 4526 威威猫系列故事——拼车记
    HDU 3336 Count the string 查找匹配字符串
    Linux command line exercises for NGS data processing
    肿瘤基因组学数据库终结者:cBioPortal---转载
    lncRNA研究利器之"TANRIC"
    Python的collections模块中的OrderedDict有序字典
    python set
  • 原文地址:https://www.cnblogs.com/00isok/p/10704118.html
Copyright © 2011-2022 走看看