最小费用最大流是指整个容量网络在保证流量最大的情况下使花费的费用最小,所以说与求最大流的思想有所差异。
我们知道,求最大流的思想是每次找一条增广路进行贪心直到贪不动为止,但是对于最小费用最大流这个问题来说,我们最后求得的一定是最大流,因此我们仍然每次贪心,只需保证费用最小即可。
于是我们使用SPFASPFASPFA而不是bfsbfsbfs来找最短增广路,我们在进行SPFASPFASPFA算法的同时用一个predpredpred的数组来记录对于当前节点uuu,从s−>us->us−>u路径上离uuu最近的点,即uuu的前驱,最后从ttt开始沿着前驱修改边上的容量即可,这个时候我们并不需要使用dfsdfsdfs进行贪心,因为在进行若干次操作后一定会最大流
#include<bits/stdc++.h>
#define inf 0x7f
#define N 5005
#define M 50005
using namespace std;
int first[N],cnt=-1,n,m,s,t,d[N],pred[N],flow[N],in[N],pos[N];
struct Node{int v,next,c,w;}e[M<<1];
inline void add(int u,int v,int c,int w){
e[++cnt].v=v;
e[cnt].c=c;
e[cnt].w=w;
e[cnt].next=first[u];
first[u]=cnt;
}
inline bool spfa(){
queue<int>q;
q.push(s);
memset(d,inf,sizeof(d));
memset(flow,inf,sizeof(flow));
memset(in,0,sizeof(in));
in[s]=1,pred[t]=-1,d[s]=0;
while(!q.empty()){
int x=q.front();
q.pop(),in[x]=0;
for(int i=first[x];i!=-1;i=e[i].next){
int v=e[i].v;
if(e[i].c>0&&d[v]>d[x]+e[i].w){
d[v]=d[x]+e[i].w;
pred[v]=x;
pos[v]=i;
flow[v]=min(flow[x],e[i].c);
if(!in[v]){
in[v]=1;
q.push(v);
}
}
}
}
return pred[t]!=-1;
}
inline void solve(){
int maxnf=0,maxnw=0;
while(spfa()){
maxnf+=flow[t];
maxnw+=flow[t]*d[t];
int pot=t;
while(pot!=s){
e[pos[pot]].c-=flow[t];
e[pos[pot]^1].c+=flow[t];
pot=pred[pot];
}
}
printf("%d %d",maxnf,maxnw);
}
int main(){
memset(first,-1,sizeof(first));
scanf("%d%d%d%d",&n,&m,&s,&t);
for(int i=1;i<=m;++i){
int u,v,c,w;
scanf("%d%d%d%d",&u,&v,&c,&w);
add(u,v,c,w);
add(v,u,0,-w);
}
solve();
return 0;
}