1. 程式人生 > >最小費用最大流——小結1

最小費用最大流——小結1

bits def tro etc 博客 我們 ID LV include

最小費用最大流

模板題

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

      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