最小費用最大流——小結1
阿新 • • 發佈:2018-06-01
bits def tro etc 博客 我們 ID LV include
最小費用最大流
模板題
思路:在費用保持最小的情況下,找出最大流。
1.我們每次找到一條從源點到匯點的最短路(spfa)
2.然後找到最短路徑上剩余流量最小的邊,把整條路徑上邊的流量都減少那麽多
3.更新最小費用
4.重復操作,直到S-T無路徑
采用了學長講的優化:
SLF優化:每次入隊的時候把這個點的費用與隊首的點的費用相比較
如果比那個點的費用小,插到隊首,否則插到隊尾
代碼
#include<bits/stdc++.h> using namespace std; inlineint 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