• 上下界的网络流模板


    上下界网络流问题对于每一条边、都有流量上下限的限制

    而普通的网络流就只有上限限制

    下面分别给出几种经典上下界网络流问题的模板

    参考博文Ⅰ参考博文Ⅱ

    1、无源汇的上下界可行流

    实际也就是能否找出一个循环流、使得每个点的流入总流量 == 流出总流量

    对于原图的每一条边在网络流中容量应当为 (上界 - 下界)

    而后计算每个点流入流量的下界总和记为 in 、流出流量的下界总和记为 out

    抽象出超级源汇 ss 与 tt

    对于原图中的每一个点

    如果 in - out > 0 则 ss 与这个点连边、容量为 in - out

    如果 in - out < 0 则 这个点与 tt 连边、容量为 out - in

    最后如果 ss 的出边都满流的话、说明可行

    给出建图伪代码

    for each v in Graph

         if( in[v] - out[v] ) connect ss -> v、cap = in[v] - out[v]、FlowSum += in[v] - out[v]

         else if( in[v] - out[v] ) connect v -> tt、cap = out[v] - in[v]

    最后如果最大流 == FlowSum 则说明可行、否则不行

    LOJ 115 上下界可行流模板题

    #include<bits/stdc++.h>
    #define LL long long
    #define ULL unsigned long long
    
    #define scl(i) scanf("%lld", &i)
    #define scll(i, j) scanf("%lld %lld", &i, &j)
    #define sclll(i, j, k) scanf("%lld %lld %lld", &i, &j, &k)
    #define scllll(i, j, k, l) scanf("%lld %lld %lld %lld", &i, &j, &k, &l)
    
    #define scs(i) scanf("%s", i)
    #define sci(i) scanf("%d", &i)
    #define scd(i) scanf("%lf", &i)
    #define scIl(i) scanf("%I64d", &i)
    #define scii(i, j) scanf("%d %d", &i, &j)
    #define scdd(i, j) scanf("%lf %lf", &i, &j)
    #define scIll(i, j) scanf("%I64d %I64d", &i, &j)
    #define sciii(i, j, k) scanf("%d %d %d", &i, &j, &k)
    #define scddd(i, j, k) scanf("%lf %lf %lf", &i, &j, &k)
    #define scIlll(i, j, k) scanf("%I64d %I64d %I64d", &i, &j, &k)
    #define sciiii(i, j, k, l) scanf("%d %d %d %d", &i, &j, &k, &l)
    #define scdddd(i, j, k, l) scanf("%lf %lf %lf %lf", &i, &j, &k, &l)
    #define scIllll(i, j, k, l) scanf("%I64d %I64d %I64d %I64d", &i, &j, &k, &l)
    
    #define lson l, m, rt<<1
    #define rson m+1, r, rt<<1|1
    #define lowbit(i) (i & (-i))
    #define mem(i, j) memset(i, j, sizeof(i))
    
    #define fir first
    #define sec second
    #define VI vector<int>
    #define ins(i) insert(i)
    #define pb(i) push_back(i)
    #define pii pair<int, int>
    #define VL vector<long long>
    #define mk(i, j) make_pair(i, j)
    #define all(i) i.begin(), i.end()
    #define pll pair<long long, long long>
    
    #define _TIME 0
    #define _INPUT 0
    #define _OUTPUT 0
    clock_t START, END;
    void __stTIME();
    void __enTIME();
    void __IOPUT();
    using namespace std;
    
    const int maxn = 2000;
    const int maxm = (10405) << 1;
    struct Edge{
        int x,y,nxt;
        LL cap;
        Edge(){}
        Edge(int a,int b,LL c,LL d)
        { x=a,y=b,cap=c,nxt=d; }
    };
    
    struct Dinic{
        static const int N=maxn, M=maxm;
        static const LL INF=0x7fffffff;
        Edge e[M];
        int n,S,T,fst[N],cur[N],EdgeCnt;
        int q[N],dis[N],head,tail;
        LL MaxFlow;
    
        void Clear(int _n){
            n=_n,EdgeCnt=1;
            memset(fst,0,sizeof fst);
        }
        void AddEdge(int a,int b,LL c){
            e[++EdgeCnt]=Edge(a,b,c,fst[a]),fst[a]=EdgeCnt;
            e[++EdgeCnt]=Edge(b,a,0,fst[b]),fst[b]=EdgeCnt;
        }
        void init(){
            for (int i=1;i<=n;i++)
                cur[i]=fst[i];
        }
        void init(int _S,int _T){
            S=_S,T=_T,MaxFlow=0,init();
        }
        int bfs(){
            memset(dis,0,sizeof dis);
            head=tail=0;
            q[++tail]=T,dis[T]=1;
            while (head<tail)
                for (int x=q[++head],i=fst[x];i;i=e[i].nxt)
                    if (!dis[e[i].y]&&e[i^1].cap){
                        if (e[i].y==T)
                            return 1;
                        dis[q[++tail]=e[i].y]=dis[x]+1;
                    }
            return (bool)dis[S];
        }
        LL dfs(int x,LL Flow){
            if (x==T||!Flow)
                return Flow;
            LL now=Flow;
            for (int &i=cur[x];i;i=e[i].nxt){
                int y=e[i].y;
                if (dis[x]==dis[y]+1&&e[i].cap){
                    LL d=dfs(y,min(now,e[i].cap));
                    e[i].cap-=d,e[i^1].cap+=d,now-=d;
                    if(now==0) break;
                }
            }
            return Flow-now;
        }
        LL GetMaxFlow(int _S,int _T){
            init(_S,_T);
            while (bfs()) init(),MaxFlow+=dfs(S,INF);
            return MaxFlow;
        }
    }DC;
    
    LL in[maxn], out[maxn], low[maxm];
    
    int main(void){__stTIME();__IOPUT();
    
        int n, m;
    
        scii(n, m);
    
        DC.Clear(n+2);
    
        int ss = n+1, tt = n+2;
    
        for(int i=1; i<=m; i++){
            int u, v;
            LL upper;
            scii(u, v);
            scll(low[i], upper);
            out[u] += low[i];
            in[v] += low[i];
            DC.AddEdge(u, v, upper - low[i]);
        }
    
        LL FlowSum = 0;
        for(int i=1; i<=n; i++){
            if(in[i] - out[i] > 0) DC.AddEdge(ss, i, in[i] - out[i]), FlowSum += in[i] - out[i];
            else if(in[i] - out[i] < 0) DC.AddEdge(i, tt, out[i] - in[i]);
        }
    
        if(DC.GetMaxFlow(ss, tt) < FlowSum) puts("NO");
        else{
            puts("YES");
            for(int i=1; i<=m; i++) printf("%lld
    ", low[i] + DC.e[i<<1 | 1].cap);
        }
    
    
    
    
    __enTIME();return 0;}
    
    
    void __stTIME()
    {
        #if _TIME
            START = clock();
        #endif
    }
    
    void __enTIME()
    {
        #if _TIME
            END = clock();
            cerr<<"execute time = "<<(double)(END-START)/CLOCKS_PER_SEC<<endl;
        #endif
    }
    
    void __IOPUT()
    {
        #if _INPUT
            freopen("in.txt", "r", stdin);
        #endif
        #if _OUTPUT
            freopen("out.txt", "w", stdout);
        #endif
    }
    View Code

    2、有源汇的上下界可行流

    只要在无源汇的网络流基础上添加多一条边即可

    添加从汇到源的一条边、上界为 INF、下界为 0

    其余操作和无源汇的操作一样

    3、有源汇的上下界最大流

    上述可行流算法跑出来的并不一定是最大流

    方法就是先跑一遍有源汇的上下界可行流

    如果可行流跑出来的结果为可行则

    保持这个网络图不要变

    再跑一次从源到汇的最大流即为答案

    LOJ 116 有源汇的上下界最大流模板题

    #include<bits/stdc++.h>
    #define LL long long
    #define ULL unsigned long long
    
    #define scl(i) scanf("%lld", &i)
    #define scll(i, j) scanf("%lld %lld", &i, &j)
    #define sclll(i, j, k) scanf("%lld %lld %lld", &i, &j, &k)
    #define scllll(i, j, k, l) scanf("%lld %lld %lld %lld", &i, &j, &k, &l)
    
    #define scs(i) scanf("%s", i)
    #define sci(i) scanf("%d", &i)
    #define scd(i) scanf("%lf", &i)
    #define scIl(i) scanf("%I64d", &i)
    #define scii(i, j) scanf("%d %d", &i, &j)
    #define scdd(i, j) scanf("%lf %lf", &i, &j)
    #define scIll(i, j) scanf("%I64d %I64d", &i, &j)
    #define sciii(i, j, k) scanf("%d %d %d", &i, &j, &k)
    #define scddd(i, j, k) scanf("%lf %lf %lf", &i, &j, &k)
    #define scIlll(i, j, k) scanf("%I64d %I64d %I64d", &i, &j, &k)
    #define sciiii(i, j, k, l) scanf("%d %d %d %d", &i, &j, &k, &l)
    #define scdddd(i, j, k, l) scanf("%lf %lf %lf %lf", &i, &j, &k, &l)
    #define scIllll(i, j, k, l) scanf("%I64d %I64d %I64d %I64d", &i, &j, &k, &l)
    
    #define lson l, m, rt<<1
    #define rson m+1, r, rt<<1|1
    #define lowbit(i) (i & (-i))
    #define mem(i, j) memset(i, j, sizeof(i))
    
    #define fir first
    #define sec second
    #define VI vector<int>
    #define ins(i) insert(i)
    #define pb(i) push_back(i)
    #define pii pair<int, int>
    #define VL vector<long long>
    #define mk(i, j) make_pair(i, j)
    #define all(i) i.begin(), i.end()
    #define pll pair<long long, long long>
    
    #define _TIME 0
    #define _INPUT 0
    #define _OUTPUT 0
    clock_t START, END;
    void __stTIME();
    void __enTIME();
    void __IOPUT();
    using namespace std;
    
    const int maxn = 2000;
    const int maxm = (10405) << 1;
    const LL INF=0x7fffffff;
    
    struct Edge{
        int x,y,nxt;
        LL cap;
        Edge(){}
        Edge(int a,int b,LL c,LL d)
        { x=a,y=b,cap=c,nxt=d; }
    };
    
    struct Dinic{
        static const int N=maxn, M=maxm;
        Edge e[M];
        int n,S,T,fst[N],cur[N],EdgeCnt;
        int q[N],dis[N],head,tail;
        LL MaxFlow;
    
        void Clear(int _n){
            n=_n,EdgeCnt=1;
            memset(fst,0,sizeof fst);
        }
        void AddEdge(int a,int b,LL c){
            e[++EdgeCnt]=Edge(a,b,c,fst[a]),fst[a]=EdgeCnt;
            e[++EdgeCnt]=Edge(b,a,0,fst[b]),fst[b]=EdgeCnt;
        }
        void init(){
            for (int i=1;i<=n;i++)
                cur[i]=fst[i];
        }
        void init(int _S,int _T){
            S=_S,T=_T,MaxFlow=0,init();
        }
        int bfs(){
            memset(dis,0,sizeof dis);
            head=tail=0;
            q[++tail]=T,dis[T]=1;
            while (head<tail)
                for (int x=q[++head],i=fst[x];i;i=e[i].nxt)
                    if (!dis[e[i].y]&&e[i^1].cap){
                        if (e[i].y==T)
                            return 1;
                        dis[q[++tail]=e[i].y]=dis[x]+1;
                    }
            return (bool)dis[S];
        }
        LL dfs(int x,LL Flow){
            if (x==T||!Flow)
                return Flow;
            LL now=Flow;
            for (int &i=cur[x];i;i=e[i].nxt){
                int y=e[i].y;
                if (dis[x]==dis[y]+1&&e[i].cap){
                    LL d=dfs(y,min(now,e[i].cap));
                    e[i].cap-=d,e[i^1].cap+=d,now-=d;
                    if(now==0) break;
                }
            }
            return Flow-now;
        }
        LL GetMaxFlow(int _S,int _T){
            init(_S,_T);
            while (bfs()) init(),MaxFlow+=dfs(S,INF);
            return MaxFlow;
        }
    }DC;
    
    LL in[maxn], out[maxn], low[maxm];
    
    int main(void){__stTIME();__IOPUT();
    
        int n, m, s, t;
    
        sciiii(n, m, s, t);
    
        DC.Clear(n+2);
    
        int ss = n+1, tt = n+2;
    
        for(int i=1; i<=m; i++){
            int u, v;
            LL upper;
            scii(u, v);
            scll(low[i], upper);
            out[u] += low[i];
            in[v] += low[i];
            DC.AddEdge(u, v, upper - low[i]);
        }DC.AddEdge(t, s, INF);
    
        LL FlowSum = 0;
        for(int i=1; i<=n; i++){
            if(in[i] - out[i] > 0) DC.AddEdge(ss, i, in[i] - out[i]), FlowSum += in[i] - out[i];
            else if(in[i] - out[i] < 0) DC.AddEdge(i, tt, out[i] - in[i]);
        }
    
        if(DC.GetMaxFlow(ss, tt) < FlowSum) puts("please go home to sleep");
        else printf("%lld
    ", DC.GetMaxFlow(s, t));
    
    
    
    
    __enTIME();return 0;}
    
    
    void __stTIME()
    {
        #if _TIME
            START = clock();
        #endif
    }
    
    void __enTIME()
    {
        #if _TIME
            END = clock();
            cerr<<"execute time = "<<(double)(END-START)/CLOCKS_PER_SEC<<endl;
        #endif
    }
    
    void __IOPUT()
    {
        #if _INPUT
            freopen("in.txt", "r", stdin);
        #endif
        #if _OUTPUT
            freopen("out.txt", "w", stdout);
        #endif
    }
    View Code

    4、有源汇的上下界最小流

    跑源汇的上下界可行流一次记为 F1

    然后添加汇到源的一条边、上界为 INF、下界为 0

    添加边后再跑一次上下界可行流一次记为 F2

    若 F1 + F2 < ( 超级源点 ss 所有出边的流量之和 )

    即满流的情况、则说明可行

    最小流就是刚刚添加的从汇到源的那条边的流量

    ( 不过有点慢、要快的可以上 LOJ 提交记录里面找找快速的代码是如何实现的 )

    LOJ 117 有源汇的上下界最小流模板

    #include<bits/stdc++.h>
    #define LL long long
    #define ULL unsigned long long
    
    #define scl(i) scanf("%lld", &i)
    #define scll(i, j) scanf("%lld %lld", &i, &j)
    #define sclll(i, j, k) scanf("%lld %lld %lld", &i, &j, &k)
    #define scllll(i, j, k, l) scanf("%lld %lld %lld %lld", &i, &j, &k, &l)
    
    #define scs(i) scanf("%s", i)
    #define sci(i) scanf("%d", &i)
    #define scd(i) scanf("%lf", &i)
    #define scIl(i) scanf("%I64d", &i)
    #define scii(i, j) scanf("%d %d", &i, &j)
    #define scdd(i, j) scanf("%lf %lf", &i, &j)
    #define scIll(i, j) scanf("%I64d %I64d", &i, &j)
    #define sciii(i, j, k) scanf("%d %d %d", &i, &j, &k)
    #define scddd(i, j, k) scanf("%lf %lf %lf", &i, &j, &k)
    #define scIlll(i, j, k) scanf("%I64d %I64d %I64d", &i, &j, &k)
    #define sciiii(i, j, k, l) scanf("%d %d %d %d", &i, &j, &k, &l)
    #define scdddd(i, j, k, l) scanf("%lf %lf %lf %lf", &i, &j, &k, &l)
    #define scIllll(i, j, k, l) scanf("%I64d %I64d %I64d %I64d", &i, &j, &k, &l)
    
    #define lson l, m, rt<<1
    #define rson m+1, r, rt<<1|1
    #define lowbit(i) (i & (-i))
    #define mem(i, j) memset(i, j, sizeof(i))
    
    #define fir first
    #define sec second
    #define VI vector<int>
    #define ins(i) insert(i)
    #define pb(i) push_back(i)
    #define pii pair<int, int>
    #define VL vector<long long>
    #define mk(i, j) make_pair(i, j)
    #define all(i) i.begin(), i.end()
    #define pll pair<long long, long long>
    
    #define _TIME 0
    #define _INPUT 0
    #define _OUTPUT 0
    clock_t START, END;
    void __stTIME();
    void __enTIME();
    void __IOPUT();
    using namespace std;
    
    const int maxn = 55000 + 10;
    const int maxm = (225003 + 1000)<<1;
    const LL INF=0x7fffffff;
    
    struct Edge{
        int x,y,nxt;
        LL cap;
        Edge(){}
        Edge(int a,int b,LL c,LL d)
        { x=a,y=b,cap=c,nxt=d; }
    };
    
    struct Dinic{
        static const int N=maxn, M=maxm;
        Edge e[M];
        int n,S,T,fst[N],cur[N],EdgeCnt;
        int q[N],dis[N],head,tail;
        LL MaxFlow;
    
        void Clear(int _n){
            n=_n,EdgeCnt=1;
            memset(fst,0,sizeof fst);
        }
        void AddEdge(int a,int b,LL c){
            e[++EdgeCnt]=Edge(a,b,c,fst[a]),fst[a]=EdgeCnt;
            e[++EdgeCnt]=Edge(b,a,0,fst[b]),fst[b]=EdgeCnt;
        }
        void init(){
            for (int i=1;i<=n;i++)
                cur[i]=fst[i];
        }
        void init(int _S,int _T){
            S=_S,T=_T,MaxFlow=0,init();
        }
        int bfs(){
            memset(dis,0,sizeof dis);
            head=tail=0;
            q[++tail]=T,dis[T]=1;
            while (head<tail)
                for (int x=q[++head],i=fst[x];i;i=e[i].nxt)
                    if (!dis[e[i].y]&&e[i^1].cap){
                        if (e[i].y==T)
                            return 1;
                        dis[q[++tail]=e[i].y]=dis[x]+1;
                    }
            return (bool)dis[S];
        }
        LL dfs(int x,LL Flow){
            if (x==T||!Flow)
                return Flow;
            LL now=Flow;
            for (int &i=cur[x];i;i=e[i].nxt){
                int y=e[i].y;
                if (dis[x]==dis[y]+1&&e[i].cap){
                    LL d=dfs(y,min(now,e[i].cap));
                    e[i].cap-=d,e[i^1].cap+=d,now-=d;
                    if(now==0) break;
                }
            }
            return Flow-now;
        }
        LL GetMaxFlow(int _S,int _T){
            init(_S,_T);
            while (bfs()) init(),MaxFlow+=dfs(S,INF);
            return MaxFlow;
        }
    }DC;
    
    LL in[maxn], out[maxn], low[maxm];
    
    int main(void){__stTIME();__IOPUT();
    
        int n, m, s, t;
    
        sciiii(n, m, s, t);
    
        DC.Clear(n+2);
    
        int ss = n+1, tt = n+2;
    
        for(int i=1; i<=m; i++){
            int u, v;
            LL upper;
            scii(u, v);
            scll(low[i], upper);
            out[u] += low[i];
            in[v] += low[i];
            DC.AddEdge(u, v, upper - low[i]);
        }
    
        LL FlowSum = 0;
        for(int i=1; i<=n; i++){
            if(in[i] - out[i] > 0) DC.AddEdge(ss, i, in[i] - out[i]), FlowSum += in[i] - out[i];
            else if(in[i] - out[i] < 0) DC.AddEdge(i, tt, out[i] - in[i]);
        }
    
        LL F1 = DC.GetMaxFlow(ss, tt);
        int id = (DC.EdgeCnt + 2)>>1;
        DC.AddEdge(t, s, INF);
        LL F2 = DC.GetMaxFlow(ss, tt);
    
        if(F1+F2 < FlowSum) puts("please go home to sleep");
        else printf("%lld
    ", DC.e[id << 1 | 1].cap);
    
    
    
    
    __enTIME();return 0;}
    
    
    void __stTIME()
    {
        #if _TIME
            START = clock();
        #endif
    }
    
    void __enTIME()
    {
        #if _TIME
            END = clock();
            cerr<<"execute time = "<<(double)(END-START)/CLOCKS_PER_SEC<<endl;
        #endif
    }
    
    void __IOPUT()
    {
        #if _INPUT
            freopen("in.txt", "r", stdin);
        #endif
        #if _OUTPUT
            freopen("out.txt", "w", stdout);
        #endif
    }
    View Code

    5、有上下界的费用流

    不好意思、不会......

  • 相关阅读:
    JavaScript监听、设置全部ajax访问属性获取返回值(状态码)
    如何在Vue项目中使用vw实现移动端适配
    git 常用命令金字教程
    移动web开发之像素和DPR详解
    小程序-微信开发者工具使用
    小程序开发框架:Taro(一)基础篇
    vscode代码自动补全失效
    JS、C#编码解码
    PHP网页缓存技术
    ajaxfileupload回到json带<pre>
  • 原文地址:https://www.cnblogs.com/qwertiLH/p/9648323.html
Copyright © 2020-2023  润新知