正题
显然一条边要么增加流量,要么减少流量,增加流量相当于正着流,减少流量相当于反着流,根据c与f的关系来分段计费,对于那些原来不满足流量平衡的点,如果入度过多,那么就从S向其连容量为入度-出度的边,表示从这个点要找那么多的容量流出去,出度过多同理.
然后跑最小费用最大流即可,由于上限其实是可以到正无穷的,所以必然有解.
#include<bits/stdc++.h>
using namespace std;
const int N=110,M=1010;
struct edge{
int y,nex,f,c;
}s[M<<1];
int first[N],len=1;
int op[N],d[N],pre[N],mmin[N];
bool tf[N];
int n,m,s1,t1;
queue<int> f;
void ins(int x,int y,int f,int c){
s[++len]=(edge){y,first[x],f,c};first[x]=len;
s[++len]=(edge){x,first[y],0,-c};first[y]=len;
}
int SPFA(){
for(int i=1;i<=t1;i++) d[i]=1e9;
d[s1]=0;tf[s1]=true;mmin[s1]=1e9;
f.push(s1);
while(!f.empty()){
int x=f.front();f.pop();tf[x]=false;
for(int i=first[x];i!=0;i=s[i].nex) if(s[i].f && d[s[i].y]>d[x]+s[i].c){
d[s[i].y]=d[x]+s[i].c;
pre[s[i].y]=i;
mmin[s[i].y]=min(mmin[x],s[i].f);
if(!tf[s[i].y]) f.push(s[i].y),tf[s[i].y]=true;
}
}
if(d[t1]==1e9) return 1e9;
int now=t1;
while(now!=s1){
s[pre[now]].f-=mmin[t1];
s[pre[now]^1].f+=mmin[t1];
now=s[pre[now]^1].y;
}
return mmin[t1]*d[t1];
}
int MCMF(){
int tot=0;
while(1){
int dx=SPFA();
if(dx==1e9) break;
tot+=dx;
}
return tot;
}
int main(){
scanf("%d %d",&n,&m);s1=n+1;t1=s1+1;
int x,y,f,c;
int ans=0;
for(int i=1;i<=m;i++){
scanf("%d %d %d %d",&x,&y,&c,&f);
op[x]-=f;op[y]+=f;
if(f<=c){
if(f<c) ins(x,y,c-f,1);
ins(x,y,1e9,2);
ins(y,x,f,1);
}
else{
ans+=f-c;
ins(x,y,1e9,2);
ins(y,x,f-c,0);
ins(y,x,c,1);
}
}
for(int i=1;i<=n;i++)
if(op[i]>0) ins(s1,i,op[i],0);
else if(op[i]<0) ins(i,t1,-op[i],0);
ins(n,1,1e9,0);
printf("%d\n",ans+MCMF());
}
本文介绍了一种解决网络流中最小费用最大流问题的方法。通过构造特定的网络图,并运用SPFA算法寻找增广路径,实现从源点到汇点的最小费用流。文章详细解释了如何处理流量不平衡的情况,确保所有节点满足流量守恒原则。
10万+

被折叠的 条评论
为什么被折叠?



