最小费用最大流——小结1

Posted PaperCloud

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了最小费用最大流——小结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\\n",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\\n",maxflow,mincost);
    return 0;
}

评测情况:


 

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

 

以上是关于最小费用最大流——小结1的主要内容,如果未能解决你的问题,请参考以下文章

POJ 2195 & HDU 1533 Going Home(最小费用最大流)

费用流伪代码

模板最小费用最大流

[洛谷P3381]模板最小费用最大流

最小费用最大流问题

最小费用最大流