Codeforces708D Incorrect Flow

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

核心技巧:减少流量当成 viui 连边,同时增加就是把费用多增加一些

首先初始的边显然要连上 (ui,vi,[fi,fi]),因为一定要流,费用置为 inf 即可

  • 如果 cifi

那么首先要补到 fi,答案加上 fici

如果增加流量,两个得要一起来,连边 (ui,vi,inf,2)

如果在原来的 [ci,fi] 范围内减少流量,不需要付出额外的费用,连边 (vi,ui,fici,0)

如果还要减少,费用为 1 ,因为这时候不需要减少上限了,直接减少流量即可

  • 反之

先补到 ci 的费用只是 1,那么连 (ui,vi,cifi,1),继续就是 (ui,vi,inf,2)

往下删和上面也是一样的, 但是不需要付出两份代价,删除也是有限度的,也就是 (vi,ui,ci,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\n",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();}

posted @   没学完四大礼包不改名  阅读(65)  评论(0编辑  收藏  举报
编辑推荐:
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
点击右上角即可分享
微信分享提示