【Codeforces 708D】Incorrect Flow

上下界费用流。

题目大意:

给定一张 $n$ 个点 $m$ 条边的网络流图,其中 $1$ 为源点 $n$ 为汇点。

给出每条边的初始容量和流量。

这个流可能是错误的,可能出现初始流量超过容量,或者流量不平衡。

现在可以花费 $1$ 的代价使一条边的流量或容量增加 $1$ 或减少 $1$,问至少花费多少代价可以使流变正确。

题解:

我们显然不会闲着没事干花费代价减少容量。

一开始已经给出了初始流量,并且会有流量不平衡的情况发生,这和上下界费用流预处理后是类似的。因此我们考虑直接在原图上跑可行流进行修正。

对 $u$ 向 $v$ 的一条边,考虑 $f$ 和 $c$ 的大小关系。

若 $f\leq c$,则和一般的可行流相似,这条边的流量限制为 $[f,c]$。又考虑到可以通过代价来减少 $f$ 的限制,因此从 $v$ 向 $u$ 连容量为 $f$ 费用为 $1$ 的边。

若 $f\lt c$,则不管怎么样,我们都得花费 $f-c$ 的代价使得满足 $f\leq c$ 的基本限制。不妨都是让流量减 $1$,则此时这条边的流量限制为 $[c,c]$ 即强制满流。仍然可以继续通过代价减少流量,因此从 $v$ 向 $u$ 连容量为 $c$ 费用为 $1$ 的边。又由于 $f-c$ 的代价不一定要全部花在降流量上,可以花在升容量上,因此从 $u$ 想 $v$ 连容量 $f-c$,费用为 $0$ 的边,表示可以将降低 $1$ 的流量等价转化为升高 $1$ 的流量。

在这些情况以外,我们显然不会吃饱撑的花钱升高容量而不流流量。所以对原来的每条边,从 $u$ 向 $v$ 链容量 $+\infty$,费用为 $2$ 的边,表示一次升高容量和一次升高流量绑定。

然后跑最小费用可行流即可。

Code:

#include<cstdio>
#include<queue>
#include<algorithm>
using namespace std;
const int inf=1e9,N=1477;
queue<int>q;
int n,m,T,cost,dlt[N],cnt=1,head[N],dis[N],iter[N];
bool vis[N];
struct edge{
    int to,nxt,cap,cost;
}e[N<<1];
inline void addedge(int u,int v,int flow,int cost){
    e[++cnt]=(edge){v,head[u],flow,cost},head[u]=cnt;
    e[++cnt]=(edge){u,head[v],0,-cost},head[v]=cnt;
}
inline void addedge(int u,int v,int L,int R,int cost){
    dlt[u]-=L,dlt[v]+=L,addedge(u,v,R-L,cost);
}
int dfs(int u,int f){
    if(u==T||!f)return f;
    int ret=0;
    vis[u]=1;
    for(int&i=iter[u];i;i=e[i].nxt)
    if(e[i].cap&&!vis[e[i].to]&&dis[e[i].to]==dis[u]+e[i].cost){
        int d=dfs(e[i].to,min(f,e[i].cap));
        e[i].cap-=d,e[i^1].cap+=d,ret+=d,f-=d;
        if(!f)break;
    }
    vis[u]=0;
    return ret;
}
bool BFS(){
    for(int i=1;i<=T;++i)dis[i]=inf;
    for(q.push(0);!q.empty();){
        int u=q.front();q.pop();
        vis[u]=0;
        for(int i=head[u];i;i=e[i].nxt)
        if(e[i].cap&&dis[e[i].to]>dis[u]+e[i].cost){
            dis[e[i].to]=dis[u]+e[i].cost;
            if(!vis[e[i].to])vis[e[i].to]=1,q.push(e[i].to);
        }
    }
    if(dis[T]==inf)return 0;
    for(int i=0;i<=T;++i)iter[i]=head[i];
    while(int f=dfs(0,inf))cost+=dis[T]*f;
    return 1;
}
int main(){
    scanf("%d%d",&n,&m);
    T=n+1;
    for(int i=1;i<=m;++i){
        int u,v,f,c;
        scanf("%d%d%d%d",&u,&v,&c,&f);
        if(f>c){
            cost+=f-c;
            addedge(u,v,0,f-c,0);
            addedge(u,v,c,c,1);
            addedge(v,u,0,c,1);
        }else addedge(u,v,f,c,1),addedge(v,u,0,f,1);
        addedge(u,v,0,inf,2);
    }
    for(int i=1;i<=n;++i)
    if(dlt[i]>0)addedge(0,i,dlt[i],0);else
    if(dlt[i]<0)addedge(i,T,-dlt[i],0);
    addedge(n,1,inf,0);
    while(BFS());
    printf("%d\n",cost);
    return 0;
}