有源汇带上下界最小流

  LOj 模板

思路我就不多说了吧,和有源汇带上下界最大流一样,只不过这次是初流-残流网络最大流。关键这个模板题写的过程无限T一组,让我很绝望。在网上搜罗了很多代码,发现我有些地方可以优化。

  (1)跑dinic的时候可以使用当前弧优化

  (2)在dinic过程中,如果rest已经等于0了,直接返回。不要不管他,感觉没什么影响,其实有的数据会卡死的(千万在边权更新之后再返回)。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
const int N=5e4+10;
const int M=6e5+10;
const int inf=1LL<<30;
int ans,n,m,s,t,S,T,tot=1,sout,flow,maxflow,lin[N],in[M],A[N],d[N],cur[N];
struct node{int y,v,n;}e[M];
inline int read(){
    char ch=getchar();int num=0,f=1;
    while(!isdigit(ch)){if(ch==‘-‘) f=-1;ch=getchar();}
    while(isdigit(ch)){num=(num<<1)+(num<<3)+(ch^48);ch=getchar();}
    return num*f;
}
inline void add(int x,int y,int w){
    e[++tot].y=y;e[tot].n=lin[x];lin[x]=tot;e[tot].v=w;
    e[++tot].y=x;e[tot].n=lin[y];lin[y]=tot;e[tot].v=0;
}
inline bool bfs(int id){
    memset(d,0,sizeof(d));
    queue<int>q;
    if(id==1) q.push(S),d[S]=1;
    else q.push(t),d[t]=1;
    while(q.size()){
        int x=q.front();q.pop();
        for(int i=lin[x];i;i=e[i].n){
            int y=e[i].y;
            if(e[i].v&&!d[y]){
                d[y]=d[x]+1;
                q.push(y);
                if(id==1&&y==T) return 1;
                if(id==2&&y==s) return 1;
            }
        }
    }
    return 0;
}
inline int dinic(int x,int flow,int id){
    if(id==1&&x==T) return flow;
    if(id==2&&x==s) return flow;
    int rest=flow;
    for(int &i=cur[x];rest&&i;i=e[i].n){
        int y=e[i].y;
        if(e[i].v&&d[y]==d[x]+1){
            int k=dinic(y,min(rest,e[i].v),id);
            if(!k) d[y]=0;
            rest-=k;
            e[i].v-=k;
            e[i^1].v+=k;
            if(!rest) return flow-rest;
        }
    }
    return flow-rest;
}
int main(){
    //freopen("h.in","r",stdin);
    //freopen("h.out","w",stdout);
    n=read(),m=read(),s=read(),t=read();
    for(int i=1;i<=m;++i){
        int x=read(),y=read(),l=read(),r=read();
        add(x,y,r-l);
        A[y]+=l,A[x]-=l;
        //if(x==s) ans+=l;
    }
    S=0,T=n+1;
    for(int i=1;i<=n;++i){
        if(A[i]>0) add(S,i,A[i]),sout+=A[i];
        else if(A[i]<0) add(i,T,-A[i]);
    }
    add(t,s,inf);
    while(bfs(1)){
        for(int i=0;i<=T;++i) cur[i]=lin[i];
        while(flow=dinic(S,inf,1)) maxflow+=flow;
    }
    if(maxflow!=sout){
        printf("please go home to sleep\n");
    }else{
        ans+=e[tot].v;
        maxflow=0;
        e[tot].v=e[tot^1].v=0;
        while(bfs(2)){
            for(int i=0;i<=T;++i) cur[i]=lin[i];
            while(flow=dinic(t,inf,2)) maxflow+=flow;
        }
        ans-=maxflow;
        printf("%d\n",ans);
        //prllf("%d\n",maxflow);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/kgxw0430/p/10265040.html

时间: 2024-10-08 10:22:03

有源汇带上下界最小流的相关文章

有上下界的网络流3-有源汇带上下界最小流SGU176

题目大意:有一个类似于工业加工生产的机器,起点为1终点为n,中间生产环节有货物加工数量限制,输入u v z c, 当c等于1时表示这个加工的环节必须对纽带上的货物全部加工(即上下界都为z),c等于0表示加工上界限制为z,下界为0,求节点1(起点)最少需要投放多少货物才能传送带正常工作. 解题思路:    1.直接 增设超级源点ss和超级汇点tt并连上附加边,对 当前图 求 无源汇带上下界可行流    2.将图的汇点sd连一条容量无限制的边到图的源点st,再求一遍 无源汇带上下界可行流    3.

loj #117. 有源汇有上下界最小流

题目链接 有源汇有上下界最小流,->上下界网络流 注意细节,边数组也要算上后加到SS,TT边. 1 #include<cstdio> 2 #include<algorithm> 3 #include<cmath> 4 #include<cstring> 5 #include<iostream> 6 7 using namespace std; 8 9 const int N = 150010; 10 const int INF = 1e9;

sgu 176 Flow construction(有源汇的上下界最小流)

[题目链接] http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=11025 [模型] 有源汇点的上下界最小流.即既满足上下界又满足流量平衡的最小流量. [思路] 按照可行流构造网络.不连t->s的边先跑一遍附加源汇点的最大流,然后连t->s一条inf边,在残量网络上跑一遍最大流.第一次求最大流所以能走的边都已经流满,第二次求附加源汇点最大流t->s的流量就会尽可能小. 另外还可以二分下界mid,然后连边(T,S,mid

Flow construction SGU - 176 有源汇有上下界最小流 二分法和回流法

/** 题目:Flow construction SGU - 176 链接:https://vjudge.net/problem/SGU-176 题意: 有源汇有上下界的最小流. 给定n个点,m个管道.每个管道给出u,v,z,c.u表示起点,v表示终点,z表示容量,如果c==1,那么表示还有下界为z. 如果c==0,表示没有下界. 求从1到n的最小流. 思路: 第一种做法: 转化为无源汇求超级源S到超级汇T的最大流flow1(此时从s出发的流和为flow1),然后讲t到s的边删掉(可以使流量等于

sgu176 Flow Construction【有源汇有上下界最小流】

同样是模板题. 首先将有源汇转换为无源汇,假设原来的源汇为st,我们加入的源汇为ST,那么我们应该从t到s连一条流量为+∞的边,使原来的st满足收支平衡,退化为普通节点. 分离必要边和其他边,从S到T跑最大流,所有与源或者汇相连的边都流满则证明有解. 去掉t到s容量为+∞的边,去掉必要边,从t到s跑最大流. 把得到的答案相减即可. 如果我们得到的答案是负的,那么说明它内部t到s连成了环,那么我们加上S到s容量为-ans的边,跑S到t的最大流,这样所有的边的流量应该就是0,再加上流量下界即为答案.

#117. 有源汇有上下界最小流

题目描述 n nn 个点,m mm 条边,每条边 e ee 有一个流量下界 lower(e) \text{lower}(e)lower(e) 和流量上界 upper(e) \text{upper}(e)upper(e),给定源点 s ss 与汇点 t tt,求源点到汇点的最小流. 输入格式 第一行两个正整数 n nn.m mm.s ss.t tt. 之后的 m mm 行,每行四个整数 s ss.t tt.lower \text{lower}lower.upper \text{upper}uppe

有源汇有上下界最小流 (ZQU 1592)

这道题跟求最大流的时候差不多. 都是先构造可行流,然后判断是否可行, 可行的话,就利用残余流量,构造从汇点t跑到源点s的最大流, 如何求出答案呢. 在第一次求可行流的dinic后,跟求最大流的时候一样,从t到s是可行流的流量: 这个时候t到s的反向边,也就是s到t的流量就是t到s流的量(因为t到s定义权值为inf,要从这条边算出来,得用inf去减到这条边剩下的才是答案,有点麻烦) 所以反向边是个便捷的求法. 所以在第一次dinic之后,t到s的反向便的流量就是可行流的流量: 然后我们再从t到s跑

【HDU 4940】Destroy Transportation system(数据水/无源无汇带上下界可行流)

Description Tom is a commander, his task is destroying his enemy’s transportation system. Let’s represent his enemy’s transportation system as a simple directed graph G with n nodes and m edges. Each node is a city and each directed edge is a directe

ZOJ3229 Shoot the Bullet(有源汇的上下界最大流)

#pragma warning(disable:4996) #include <iostream> #include <cstring> #include <string> #include <vector> #include <cstdio> #include <algorithm> #include <cmath> #include <queue> #include <map> #include