反向边的技巧还是非常不错的……
核心技巧:减少流量当成 (v_i o u_i) 连边,同时增加就是把费用多增加一些
首先初始的边显然要连上 ((u_i,v_i,[f_i,f_i])),因为一定要流,费用置为 (-inf) 即可
- 如果 (c_ile f_i)
那么首先要补到 (f_i),答案加上 (f_i-c_i)
如果增加流量,两个得要一起来,连边 ((u_i,v_i,inf,2))
如果在原来的 ([c_i,f_i]) 范围内减少流量,不需要付出额外的费用,连边 ((v_i,u_i,f_i-c_i,0))
如果还要减少,费用为 (1) ,因为这时候不需要减少上限了,直接减少流量即可
- 反之
先补到 (c_i) 的费用只是 (1),那么连 ((u_i,v_i,c_i-f_i,1)),继续就是 ((u_i,v_i,inf,2))
往下删和上面也是一样的, 但是不需要付出两份代价,删除也是有限度的,也就是 ((v_i,u_i,c_i,1))
最后上个最小费用最大流
注意:
一开始给加入的边费用为负即可,而且负的尽量小
否则会爆运算
Code
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define reg register
#define inf 1e18
namespace yspm{
inline int read(){
int res=0,f=1; char k;
while(!isdigit(k=getchar())) if(k=='-') f=-1;
while(isdigit(k)) res=res*10+k-'0',k=getchar();
return res*f;
}
const int E=4e3+10,N=1010;
struct node{int to,nxt,lim,cst;}e[E<<1];
int head[N],cnt=1,d[N],ct,incf[N],pre[N],n,ans,S,T,m; bool vis[N]; queue<int> q;
inline void adde(int u,int v,int w,int c){
e[++cnt].to=v; e[cnt].nxt=head[u]; e[cnt].lim=w; e[cnt].cst=c;
return head[u]=cnt,void();
}
inline int min(int x,int y){return x<y?x:y;}
inline void add(int u,int v,int w,int c){return adde(u,v,w,c),adde(v,u,0,-c);}
inline bool spfa(){
for(reg int i=1;i<=n+2;++i) d[i]=inf; d[S]=0; incf[S]=inf; q.push(S); vis[S]=1;
while(q.size()){
int fr=q.front(); vis[fr]=0; q.pop();
for(reg int i=head[fr];i;i=e[i].nxt){
int t=e[i].to; if(!e[i].lim||d[fr]+e[i].cst>=d[t]) continue;
d[t]=d[fr]+e[i].cst; pre[t]=i; incf[t]=min(incf[fr],e[i].lim);
if(!vis[t]) vis[t]=1,q.push(t);
}
} return d[T]!=inf;
}
inline void EK(){
while(spfa()){
int x=T; while(x!=S) e[pre[x]].lim-=incf[T],e[pre[x]^1].lim+=incf[T],x=e[pre[x]^1].to;
ans+=incf[T]*d[T];
} return printf("%lld
",ans),void();
}
signed main(){
n=read(); m=read(); S=n+1; T=S+1;
for(reg int i=1,u,v,f,c;i<=m;++i){
u=read(); v=read(); c=read(); f=read();
add(S,v,f,-1e5); add(u,T,f,-1e5); ans+=f*2e5;
if(f<=c) add(u,v,c-f,1),add(u,v,inf,2),add(v,u,f,1);
else ans+=f-c,add(v,u,c,1),add(u,v,inf,2),add(v,u,f-c,0);
} add(n,1,inf,0); EK();
return 0;
}
}
signed main(){return yspm::main();}