Codeforces708D Incorrect Flow

反向边的技巧还是非常不错的……

核心技巧:减少流量当成 (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();}

原文地址:https://www.cnblogs.com/yspm/p/14353571.html