最小费用最大流——小结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的主要内容,如果未能解决你的问题,请参考以下文章