网络流之最小费用最大流
最小费用最大流?
最小费用最大流就是在最大流的基础上,给每条边一个单位花费,要在保证是最大流的情况下找出最小费用。这里的单位花费就是这条边的每一单位流量的花费。
解法:
先看这里的花费,假设第i条边的花费是wi,那么假设找到 了一条增广路(与最大流中的意义相同),且这条增广路的流量为x,那么这条增广路第i条边的花费就是x*wi,将x提出来,就可以得到整条增广路的花费就是,这i条边的单位花费之和*流量x。因为最大流是一定的了(因为要先保证找到的是最大流),那么只要这条增广路上的总的单位花费最小就可以了。这样就可以用spfa来跑最短路代替最大流中的dfs找增广路,这样就可以缩小费用了。其他的思路基本上与最大流相同,用增广路上的每条边减去这条路上的最小边,用其反边加上这条边。
然后就是将总的花费记录下来,按照上面的思路,在用spfa找增广路时,会用一个dis数组来记录下从s(起点)开始到每个点的最短路,然后用dis[t(终点)]*x(流量),就可以得到这条增广路的花费,然后将其累加起来,就找到了总花费。最后print就可以了、、、、
具体实现的时候还要考虑到找到增广路之后怎么对它在进行操作(也就是找最小流量和增流),可以在spfa的时候用一个faz数组记录下每个点最优方案下的父亲,然后再次遍历的时候就从t(终点)开始倒着找爸爸。
一道例题:luogu3381
代码:
#include<queue> #include<cstring> #include<cstdio> #include<deque> #include<iostream> using namespace std; const int N=5010*2,M=50010*2; deque<int>q; struct node { int v,w,nxt,cost; }edg[M]; int ejs,n,m,s,t,head[N],ans_cost,ans_w,dis[N],faz[N],map[N],inqu[N]; void add(int u,int v,int w,int cost) { edg[++ejs].v=v; edg[ejs].w=w; edg[ejs].cost=cost; edg[ejs].nxt=head[u]; head[u]=ejs; } int change(int x) { if(x%2) return x+1; return x-1; } bool spfa() { memset(faz,0,sizeof(faz)); memset(inqu,0,sizeof(inqu)); memset(dis,0x3f,sizeof(dis)); memset(map,0,sizeof(map)); while(!q.empty()) q.pop_front(); q.push_back(s); dis[s]=0; inqu[s]=1; while(!q.empty()) { int u=q.front(); inqu[u]=0; q.pop_front(); for(int i=head[u];i;i=edg[i].nxt) { int v=edg[i].v; if(dis[v]>dis[u]+edg[i].cost&&edg[i].w>0) { dis[v]=dis[u]+edg[i].cost; faz[v]=u; map[v]=i; if(!inqu[v]) { if(!q.empty()) { int k=q.front(); if(dis[v]<dis[k]) q.push_front(v); else q.push_back(v); } else q.push_back(v); inqu[v]=1; } } } } if(faz[t]) return 1; else return 0; } void work() { while(spfa()) { int x=0x7fffffff,now=t; while(now!=s) { x=min(x,edg[map[now]].w); now=faz[now]; } now=t; ans_w+=x; ans_cost+=dis[t]*x; while(now!=s) { edg[map[now]].w-=x; edg[change(map[now])].w+=x; now=faz[now]; } } } int main() { scanf("%d%d%d%d",&n,&m,&s,&t); for(int i=1,x,y,a,b;i<=m;++i) { scanf("%d%d%d%d",&x,&y,&a,&b); add(x,y,a,b); add(y,x,0,-b); } work(); printf("%d %d",ans_w,ans_cost); return 0; }
PS:这个代码中用到了双端队列deque来优化spfa