题目描述:
给出一个网络图,以及其源点和汇点,每条边已知其最大流量和单位流量费用,求出其网络最大流和在最大流情况下的最小费用。
题解:
这是最小费用最大流模板。
对于EK算法,我们可以通过bfs找出增广路径然后解出最大流。
但是最大流值是一定的,流法却有很多。
我们可以将每条边费用作这条边的边长,用spfa求出最短增广路。
其实就是将EK中的bfs换成spfa。
代码:
#include<queue> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define N 5050 #define M 50050 inline int rd() { int f=1,c=0;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){c=10*c+ch-'0';ch=getchar();} return f*c; } int n,m,S,T,hed[N],cnt=-1; struct EG { int to,nxt,vl,w; }e[2*M]; void ae(int f,int t,int v,int w) { e[++cnt].to = t; e[cnt].nxt = hed[f]; e[cnt].vl = v; e[cnt].w = w; hed[f]=cnt; } int maxf,minw; int dis[N],fl[N],pre[N],fa[N]; bool vis[N]; const int inf = 0x3f3f3f3f; bool spfa() { memset(dis,0x3f,sizeof(dis)); memset(fl,0,sizeof(fl)); memset(vis,0,sizeof(vis)); dis[S]=0,fl[S]=inf,vis[S]=1,pre[T]=-1; queue<int>q; q.push(S); while(!q.empty()) { int u = q.front(); q.pop(); vis[u]=0; for(int j=hed[u];~j;j=e[j].nxt) { int to = e[j].to; if(e[j].vl&&dis[to]>dis[u]+e[j].w) { dis[to]=dis[u]+e[j].w; fl[to]=min(fl[u],e[j].vl); pre[to]=j,fa[to]=u; if(!vis[to]) { vis[to]=1; q.push(to); } } } } return pre[T]!=-1; } void mcmf() { while(spfa()) { minw+=dis[T]*fl[T]; maxf+=fl[T]; int tmp = T; while(tmp!=S) { e[pre[tmp]].vl-=fl[T]; e[pre[tmp]^1].vl+=fl[T]; tmp=fa[tmp]; } } } int main() { n=rd(),m=rd(),S=rd(),T=rd(); memset(hed,-1,sizeof(hed)); for(int f,t,v,w,i=1;i<=m;i++) { f=rd(),t=rd(),v=rd(),w=rd(); ae(f,t,v,w),ae(t,f,0,-w); } mcmf(); printf("%d %d ",maxf,minw); return 0; }