【LOJ115】无源汇有上下界可行流(模板题)

点此看题面

大致题意: 给你每条边的流量上下界,让你判断是否存在可行流。若有,则还需输出一个合法方案。

大致思路

首先,每条边既然有一个流量下界\(lower\),我们就强制它初始流量为\(lower\)

而考虑到它还有一个流量上界\(upper\),其实这就等同于建一条初始流量为\(0\),而容量为\(upper-lower\)的边。

但考虑到流量平衡,因此我们可以考虑对于每个点用\(v_i\)记录下其流量的不平衡值,即对于一条边\(x->y\),我们将\(v_x\)减去\(lower\),将\(v_y\)加上\(lower\)

在所有边加完后,对于所有\(v_i\)不等于\(0\)的点,如果\(v_i\)为正,则我们从源点向其连一条边权为\(v_i\)的边;如果\(v_i\)为负,则我们由其向汇点连一条边权为\(-v_i\)的边。

然后跑最大流。

如果能流满,就说明存在可行流,输出\(YES\),方案就是每条边当前流量加上其初始的下界\(lower\)

否则,输出\(NO\)

代码

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 200
#define M 10200
#define INF 1e9
#define min(x,y) ((x)<(y)?(x):(y))
using namespace std;
int n,m;
class FastIO
{
    private:
        #define FS 100000
        #define tc() (A==B&&(B=(A=FI)+fread(FI,1,FS,stdin),A==B)?EOF:*A++)
        #define tn (x<<3)+(x<<1)
        #define D isdigit(c=tc())
        char c,*A,*B,FI[FS];
    public:
        I FastIO() {A=B=FI;}
        Tp I void read(Ty& x) {x=0;W(!D);W(x=tn+(c&15),D);}
        Ts I void read(Ty& x,Ar&... y) {read(x),read(y...);}
}F;
class UpperLowerFeasibleFlow_without_ST//无源汇有上下界可行流
{
    private:
        #define add(x,y,v) (e[++ee].nxt=lnk[x],e[lnk[x]=ee].to=y,e[ee].Cap=v)
        #define AddOneWayEdge(x,y,v) (add(x,y,v),add(y,x,0))
        static Con int Psz=N,Lsz=N+M<<1;int ee,iv[Lsz+5],lnk[Psz+5],cur[Psz+5],v[Psz+5],q[Psz+5],dep[Psz+5];
        struct edge {int to,nxt,Cap;}e[Lsz+5];
        I bool BFS()//BFS找增广路
        {
            RI i,k,H=1,T=1;memset(dep,0,sizeof(dep)),dep[q[1]=s]=1;W(H<=T&&!dep[t])
                for(i=lnk[k=q[H++]];i;i=e[i].nxt) e[i].Cap&&!dep[e[i].to]&&(dep[q[++T]=e[i].to]=dep[k]+1);
            return dep[t]?(memcpy(cur,lnk,sizeof(lnk)),true):false;
        }
        I int DFS(CI x,RI f)//DFS统计流量
        {
            if(!(x^t)||!f) return f;RI i,t,res=0;
            for(i=cur[x];i;i=e[i].nxt)
            {
                if(cur[x]=i,(dep[x]+1)^dep[e[i].to]||!(t=DFS(e[i].to,min(f,e[i].Cap)))) continue;
                if(e[i].Cap-=t,e[((i-1)^1)+1].Cap+=t,res+=t,!(f-=t)) break;
            }return !res&&(dep[x]=-1),res;
        }
    public:
        int s,t;I UpperLowerFeasibleFlow_without_ST() {s=1,t=2;}I int P(CI x) {return x+2;}
        I void Add(CI p,CI x,CI y,CI Lower,CI Upper) {iv[p]=Lower,AddOneWayEdge(x,y,Upper-Lower),v[x]-=Lower,v[y]+=Lower;}
        I void Build(CI n) {for(RI i=3;i<=n+2;++i) v[i]>0&&AddOneWayEdge(s,i,v[i]),v[i]<0&&AddOneWayEdge(i,t,-v[i]);}//对于所有v[i]不等于0的点进行连边操作
        I void FeasibleFlow()//求出一个可行流 
        {
            W(BFS()) DFS(s,INF);RI i;for(i=lnk[s];i;i=e[i].nxt) if(e[i].Cap) return (void)(puts("NO"));//如果没流满,输出NO
            for(puts("YES"),i=1;i<=m;++i) printf("%d\n",iv[i]+e[i<<1].Cap);//输出这条边的下界lower与它的流量的和
        }
}V;
int main()
{
    RI i,x,y,Lower,Upper;for(F.read(n,m),i=1;i<=m;++i) F.read(x,y,Lower,Upper),V.Add(i,V.P(x),V.P(y),Lower,Upper);//读入+建边
    return V.Build(n),V.FeasibleFlow(),0;//求答案
}

转载于:https://www.cnblogs.com/chenxiaoran666/p/LOJ115.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值