zoukankan      html  css  js  c++  java
  • 最小费用最大流——小结1

    最小费用最大流

    模板题

    思路:在费用保持最小的情况下,找出最大流。

          1.我们每次找到一条从源点到汇点的最短路(spfa)

          2.然后找到最短路径上剩余流量最小的边,把整条路径上边的流量都减少那么多

          3.更新最小费用

          4.重复操作,直到S-T无路径

    采用了学长讲的优化:

        SLF优化:每次入队的时候把这个点的费用与队首的点的费用相比较

             如果比那个点的费用小,插到队首,否则插到队尾

                          

    代码

    #include<bits/stdc++.h>
    using namespace std;
    inline int read(){
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
        return x*f;
    }
    #define inf 0x3f3f3f3f
    #define MN 5005
    #define ME 100005
    int n,m,S,T;
    int q[ME*2+5],tp,tl,ans,from[MN+5],d[MN+5],hr[MN+5],cnt=1,res;
    bool inq[MN+5];
    struct edge{int fr,to,nex,w,c;}e[ME];
    inline void ins(int f,int t,int w,int c){
        e[++cnt]=(edge){f,t,hr[f],w,c};hr[f]=cnt;
        e[++cnt]=(edge){t,f,hr[t],0,-c};hr[t]=cnt;
    }
    inline bool spfa(){
        register int i;
        memset(d,0x3f,sizeof d);
        memset(inq,0,sizeof inq);
        q[tp=tl=MN]=S;inq[S]=1;d[S]=0;
        while(tp>=tl){
            int u=q[tl++];inq[u]=0;
            for(i=hr[u];i;i=e[i].nex)
            if(e[i].w>0&&d[u]+e[i].c<d[e[i].to]){
                d[e[i].to]=d[u]+e[i].c;from[e[i].to]=i;
                if(!inq[e[i].to]){
                    if(d[e[i].to]<d[q[tl]]) q[--tl]=e[i].to;
                    else q[++tp]=e[i].to; inq[e[i].to]=1;
                }
            }
        }
        return d[T]!=inf;
    }
    inline void mcf(){
        int minn=inf,i;
        for(i=from[T];i;i=from[e[i].fr])
            minn=min(minn,e[i].w);
        res+=minn;
        for(i=from[T];i;i=from[e[i].fr]){
            ans+=minn*e[i].c;
            e[i].w-=minn;e[i^1].w+=minn;
        }
    }
    int main(){
        register int u,v,w,c,i;
        n=read(),m=read();S=read(),T=read();
        for(i=1;i<=m;i++){
            u=read(),v=read(),w=read(),c=read();
            ins(u,v,w,c);
        }
        while(spfa()) mcf();
        printf("%d %d
    ",res,ans);
        return 0;
    }

    评测情况:

    补充:

      1.其实费用流同样可以多路增广。

      2.实践证明,spfa时,从T到S反过来操作会快很多

    代码

    #include<bits/stdc++.h>
    using namespace std;
    inline int read(){
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
        return x*f;
    }
    #define inf 0x3f3f3f3f
    #define ME 100005
    #define MN 5005
    int n,m,S,T,maxflow,mincost;
    struct edge{int to,w,c,nex;}e[ME];int hr[MN],cnt=1;
    
    inline void ins(int f,int t,int w,int c){
        e[++cnt]=(edge){t,w,c,hr[f]};hr[f]=cnt;
        e[++cnt]=(edge){f,0,-c,hr[t]};hr[t]=cnt; 
    }
    int d[MN],q[ME],l,r;
    bool inq[MN],vis[MN];
    
    bool spfa(){
        memset(d,0x3f,sizeof d);
        q[l=r=MN]=T;d[T]=0;inq[T]=1;
        while(l<=r){
            int u=q[l++];inq[u]=0;
            for(int i=hr[u];i;i=e[i].nex)
            if(e[i^1].w&&d[e[i].to]>d[u]-e[i].c){
                d[e[i].to]=d[u]-e[i].c;
                if(!inq[e[i].to])
                d[e[i].to]<d[q[l]]?q[--l]=e[i].to:q[++r]=e[i].to,inq[e[i].to]=1;
            }
        }
        return d[S]!=inf;
    }
    
    int flow(int x,int f){
        vis[x]=1;
        if(x==T) return f;
        int used=0,w;
        for(int i=hr[x];i;i=e[i].nex)
            if(!vis[e[i].to]&&d[x]-e[i].c==d[e[i].to]&&e[i].w){
                w=flow(e[i].to,min(f-used,e[i].w));
                used+=w;mincost+=w*e[i].c;
                e[i].w-=w,e[i^1].w+=w;
                if(f==used) return f;
            }
        return used;
    }
    
    inline void solve(){
        while(spfa()){
            do{
                memset(vis,0,sizeof vis);
                maxflow+=flow(S,inf);
            }while(vis[T]);
        }
    }
    
    int main(){
        int i,u,v,y,z;
        n=read(),m=read(),S=read(),T=read();
        for(i=1;i<=m;i++){
            u=read(),v=read(),y=read(),z=read();
            ins(u,v,y,z);
        }
        solve();
        printf("%d %d
    ",maxflow,mincost);
        return 0;
    }

    评测情况:


    来自PaperCloud的博客,未经允许,请勿转载,TKS!

  • 相关阅读:
    atitit查询表修改表字段没反应--解锁锁定的表
    atitit.自适应设计悬浮图片的大小and 位置
    .net 科学类型相关问题
    js eval()执行传参函数的写法
    oracle里如何将两个日期的时间差返回**时**分的格式
    .NET开源项目介绍及资源推荐:数据持久层
    highCharts 电流表、电压表
    win7 telnet命令无法使用
    ascx aspx ashx asmx 文件的作用
    Oracle 新建序列值
  • 原文地址:https://www.cnblogs.com/PaperCloud/p/9121010.html
Copyright © 2011-2022 走看看