【网络流】CF708D Incorrect Flow
作者:互联网
思考过程。无脑记录。
流量守恒:记 \(d(x)=in_x-out_x,d(x)=0\),因为上下界网络流经常这么表示,当然记 \(d(x)=out_x-in_x\) 也行。
减容量是可以舍弃的操作,因为减容量总是可以使用减流量解决或者会使其更不优。
再者,每条边给定的原始流量一定要先流满再说,所以上下界都是 \(f\)。
下面都省略了下界 0。
\(f \le c\),那么在不增加 \(c\) 的情况下,\(f\) 还能加 \(c-f\),考虑对 \(d(u),d(v)\) 的影响,假如加了 \(l\),那么 \(d(u)-=l,d(v)+=l\)。考虑这个式子如何建模吧。若原来的 \(d(x)>0,x\in [1,n]\) 说明入流多,要流出。对应的,对 \(d(x)<0\) 的,要流入,这部分有助于建模思考。考虑加 1,那么就是 \((u,v,c-f,1)\),即假如需要流经这条边,则会给 \(u\) 提供流出流量,给 \(v\) 提供流入流量。考虑减 1,那么就是对称的 \((v,u,f,1)\)。再考虑下当 \(f=c\) 的时候,这时候我们要增加流量的话,只能加容量再加流量,即花费 2。那么就是 \((u,v,+\infty,2)\)。
\(f>c\),欸,我不会,睡觉了。
考虑增加流量,那么先要增加 \(f-c\) 的容量(这东西我还没想明白咋建模,主要是这个花费应该只能后面跑完在算吧),且后面每次增加流量都要增加容量,即 \((u,v,+\infty,2)\)。减少流量,那么先要减少 \(f-c\) 的流量,再 \((v,u,c,1)\)。好像漏了些,不懂。。。
总算明白了,\(c\le f'\le f\) 也算一种情况,那么 \((f-f')+(f'-c)=f-c\),花费始终是 \(f-c\) 的,所以无论如何 \(f>c\) 的情况都有一个固定原始花费。那么这样子算减少流量,即 \((v,u,f-c,0)\),即最多可以减少这么多,因为只要保证 \(c\le f'\le f\) 即可。
#include <bits/stdc++.h>
#define int long long
#define inf (int)(2e15)
using namespace std;
int rd() {
int f=1,sum=0; char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-1; ch=getchar();}
while(isdigit(ch)) {sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
return sum*f;
}
#define N (int)(2e5+5)
struct edge {
int nex,to,w,c;
}e[N<<1];
int chea[N],hea[N],d[N],cnt=1,n,m,ans,S,T,s,t;
void add_edge(int x,int y,int z,int c) {
e[++cnt].nex=hea[x]; e[cnt].to=y; e[cnt].w=z; e[cnt].c=c; hea[x]=cnt;
}
void add(int x,int y,int z,int c) {
add_edge(x,y,z,c); add_edge(y,x,0,-c);
}
void lradd(int x,int y,int l,int r,int c) {
add(x,y,r-l,c); d[x]-=l; d[y]+=l;
}
namespace WLL {
queue<int>q;
int dis[N],S,T;
bool vis[N];
bool spfa() {
for(int i=0;i<=T;i++) dis[i]=inf,vis[i]=0;
dis[S]=0; q.push(S);
while(!q.empty()) {
int x=q.front(); q.pop();
vis[x]=0;
for(int i=hea[x];i;i=e[i].nex) {
int y=e[i].to;
if(e[i].w&&dis[y]>dis[x]+e[i].c) {
dis[y]=dis[x]+e[i].c;
if(!vis[y]) vis[y]=1,q.push(y);
}
}
}
return dis[T]<inf;
}
int dfs(int x,int lim) {
if(x==T||!lim) return lim;
int flow=0,fl;
vis[x]=1;
for(int i=hea[x];i&&lim;i=e[i].nex) {
int y=e[i].to;
if(e[i].w&&!vis[y]&&dis[y]==dis[x]+e[i].c) {
fl=dfs(y,min(lim,e[i].w));
if(!fl) continue;
flow+=fl; lim-=fl; e[i].w-=fl; e[i^1].w+=fl;
ans+=e[i].c*fl;
}
}
if(!flow) dis[x]=inf;
vis[x]=0;
return flow;
}
void zkw(int ss,int tt) {
S=ss; T=tt;
while(spfa()) {
memset(vis,0,sizeof(int)*(T+2));
dfs(S,inf);
}
}
}
signed main() {
n=rd(); m=rd(); s=1; t=n; S=0; T=n+1;
for(int i=1;i<=m;i++) {
int x=rd(),y=rd(),c=rd(),f=rd();
lradd(x,y,f,f,0);
if(f<=c) {
lradd(x,y,0,c-f,1);
lradd(y,x,0,f,1);
lradd(x,y,0,inf,2);
} else {
ans+=f-c;
lradd(x,y,0,inf,2);
lradd(y,x,0,c,1);
lradd(y,x,0,f-c,0);
}
}
lradd(t,s,0,inf,0);
for(int i=1;i<=n;i++) {
if(d[i]>0) add(S,i,d[i],0);
else if(d[i]<0) add(i,T,-d[i],0);
}
WLL::zkw(S,T);
printf("%lld",ans);
return 0;
}
标签:Incorrect,le,CF708D,int,Flow,流量,vis,ch,dis 来源: https://www.cnblogs.com/xugangfan/p/15872282.html