类似EK算法,只是将bfs改成spfa,求最小花费。
为什么可以呢,加入1-3-7是一条路,求出一个流量为40,那么40*f[1]+40*f[2]+40*f[3],f[1]是第一条路的单位费用,f[2]是。。。
因此可以写成40*(f[1]+f[2]+f[3]),那么f[1]+f[2]+..
ek算法不管先走那条路,最后一定都是最大流maxflow,那么费用是maxflow*路径费用,因此,在保证最大流的前提下,转换成了求最小费用的问题。
即求最短路类似。
另外,为什么可以这样求最小费用最大流呢,因为ek告诉你一定是从源点到汇点有一条可行路,既然每次都要选一条,一定要选最小费用的才最优。
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<queue> using namespace std; const int maxn=100010; int n,m,s,t,cnt,hd[maxn],dis[maxn],flow[maxn],vis[maxn],pre[maxn],last[maxn]; queue<int> q; struct Edge{ int to,nxt,flow,dis; }edge[maxn]; void add(int u,int v,int w,int dis) { cnt++; edge[cnt].to=v; edge[cnt].nxt=hd[u]; edge[cnt].flow=w; edge[cnt].dis=dis; hd[u]=cnt; } int spfa(int s,int t) { memset(dis,0x7f,sizeof dis); memset(flow,0x7f,sizeof flow); memset(vis,0,sizeof vis); // while(!q.empty()) q.pop(); q.push(s),vis[s]=1,dis[s]=0,pre[t]=-1; while(!q.empty()) { int u=q.front(); q.pop(); vis[u]=0; for(int i=hd[u];i!=-1;i=edge[i].nxt) { int v=edge[i].to; if(edge[i].flow >0 && dis[v]>dis[u]+edge[i].dis) { dis[v]=dis[u]+edge[i].dis; pre[v]=u; last[v]=i;// flow[v]=min(flow[u],edge[i].flow);// if(!vis[v]) { vis[v]=1; q.push(v); } // if(v==t) return 1;//已经到达,但不一定是最短路,晕,哈哈想成之前的bfs了。。。 } } } // return 0; return pre[t]!=-1; } int mxflow=0,mincost=0; void mcmf() { while(spfa(s,t))//往下走就一定能到达 { int now=t; mxflow+=flow[t]; mincost+=flow[t]*dis[t]; while(now!=s) { edge[last[now]].flow-=flow[t]; edge[last[now]^1].flow+=flow[t]; now=pre[now]; } } } int x,y,z,f; int main() { scanf("%d%d%d%d",&n,&m,&s,&t); memset(hd,-1,sizeof hd);cnt=-1; for(int i=1;i<=m;i++) { scanf("%d%d%d%d",&x,&y,&z,&f); add(x,y,z,f); add(y,x,0,-f);//顺着流一单位,逆着流一单位,相当于没流 } mcmf(); printf("%d %d",mxflow,mincost); }