有(无)源汇 有上下界可行流 模板

//无源汇有上下界可行流(循环流)
/*
模型:一个网络,求出一个流,使得每条边的流量必须>=Li且<=Hi,每个点必须满足总流入量=总流出量(流量守恒)(这个流的特点是循环往复,无始无终)
可行流算法的核心是将一个不满足流量守恒的初始流调整成满足流量守恒的流.
流量守恒,即每个点的总流入量=总流出量
如果存在一个可行流,那么一定满足每条边的流量都大于等于流量的下限.因此我们可以令每条边的流量等于流量下限,得到一个初始流,然后建出这个流的残量网络.
 (即:每条边的流量等于这条边的流量上限与流量下限之差)这个初始流不一定满足流量守恒,因此最终的可行流一定是在这个初始流的基础上增大了一些边的流量使得所有点满足流量守恒.
*/
#include <bits/stdc++.h>
using namespace std;
const int maxn=300,maxm=100000;
struct edge{
    int to,next,w,num;
}lst[maxm];int len=0,first[maxn],_first[maxn];
void addedge(int a,int b,int w,int num){
    lst[len].num=num;
    lst[len].to=b;lst[len].next=first[a];lst[len].w=w;first[a]=len++;
    lst[len].num=num;
    lst[len].to=a;lst[len].next=first[b];lst[len].w=0;first[b]=len++;
}
int vis[maxn],dis[maxn],q[maxn],head,tail,s,t,T;
bool bfs(){
    vis[s]=++T;dis[s]=1;head=tail=0;q[tail++]=s;
    while(head!=tail){
        int x=q[head++];
        for(int pt=first[x];pt!=-1;pt=lst[pt].next){
            if(lst[pt].w&&vis[lst[pt].to]!=T){
                vis[lst[pt].to]=T;dis[lst[pt].to]=dis[x]+1;q[tail++]=lst[pt].to;
            }
        }
    }
    if(vis[t]==T)memcpy(_first,first,sizeof(first));
    return vis[t]==T;
}
int dfs(int x,int lim){
    if(x==t){
        return lim;
    }
    int flow=0,a;
    for(int pt=_first[x];pt!=-1;pt=lst[pt].next){
        _first[x]=pt;
        if(lst[pt].w&&dis[lst[pt].to]==dis[x]+1&&(a=dfs(lst[pt].to,min(lst[pt].w,lim-flow)))){
            lst[pt].w-=a;lst[pt^1].w+=a;flow+=a;
            if(flow==lim)return flow;
        }
    }
    return flow;
}
int dinic(){
    int ans=0,x;
    while(bfs())
        while(x=dfs(s,0x7f7f7f7f))ans+=x;
    return ans;
}
int low[maxm],ans[maxm];
int totflow[maxn],n,m;
void work(){
    memset(totflow,0,sizeof(totflow));
    memset(first,-1,sizeof(first));len=0;
    scanf("%d%d",&n,&m);
    int u,v,b;
    s=0;t=n+1;
    for(int i=1;i<=m;++i){
        scanf("%d%d%d%d",&u,&v,&low[i],&b);//u v 下界 上界
        addedge(u,v,b-low[i],i);totflow[u]-=low[i];totflow[v]+=low[i];
    }
    int sum=0;
    for(int i=1;i<=n;++i){
        if(totflow[i]<0){
            addedge(i,t,-totflow[i],0);
        }else{
            sum+=totflow[i];
            addedge(s,i,totflow[i],0);
        }
    }
    if(dinic()==sum){
        puts("YES");
        for(int i=1;i<=n;++i){
            for(int pt = first[i] ; pt != -1; pt = lst[pt].next){
                if(lst[pt].num == 0 || pt % 2 == 0) continue;
                ans[lst[pt].num] = lst[pt].w + low[lst[pt].num];
            }
        }
        for(int i=1;i<=m;++i)printf("%d\n",ans[i]);//输出可行流
    }
    else puts("NO");//无可行流
}
int main(){
    work();
    return 0;
}

/*
对于有源汇上下界可行流问题
 只要加一条从T到S流量上限为inf的边即可
*/
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值