上下界网络流

区域赛在急,看看了上下界网络流,引水思源,这里给个出处 [上下界网络流]https://www.cnblogs.com/liu-runda/p/6262832.html
 这里只简单记录建图方法

无源汇可行流

建图

  1. u->v upper-lower 在源边上建容量上限为 upper-lower的边
  2. 计算每条边的 totflow[u]=in[u]out[u]
  3. 对于每个点  totflow[u]>0,s>u,totflow[u] ,反之建  i>t,totflow[i]
  4. st 最大流,如果最大流等于总需要流入的流量( totflow[u]>0totflow[u] ) 说明可行.
  5. 每条边的实际流量为low[i] + s-t 最大流跑完后边的流量

例题 zoj 2314

#include <bits/stdc++.h>
using namespace std;
#define ms(x,v) (memset((x),(v),sizeof(x)))
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define INF 0x3f3f3f3f
typedef long long LL;
typedef pair<int,int > Pair;
const int MAX_V = 200+10;
const int MAX_E = 1e5+10;
int n,m;

namespace dinic{
    int ne =0,s,t;
    struct Edge{
        int from ,to,cap;
        Edge(int u=0,int v=0,int c =0):from(u),to(v),cap(c){};
    } E[MAX_E<<2];
    std::vector<int> G[MAX_V];
    int level[MAX_V],cur[MAX_V];
    inline void add_edge(int u,int v,int cap) {
        E[ne] = Edge(u,v,cap);G[u].pb(ne++);
        E[ne] = Edge(v,u,0); G[v].pb(ne++);
    }
    void bfs(int s) {
        ms(level,-1);
        queue<int > Q;Q.push(s);
        level[s] =0;
        while (!Q.empty()) {
            int u = Q.front();Q.pop();
            for(int i=0 ; i< G[u].size() ; ++i){
                Edge &e = E[G[u][i]];
                if(e.cap >0 && level[e.to] <0){level[e.to] = level[u]+1 ; Q.push(e.to);}
            }
        }
    }
    int dfs(int v,int t,int f){
        if(v ==t || f==0)return f;
        for(int &i = cur[v] ; i<G[v].size() ; ++i){
            Edge & e = E[G[v][i]];Edge & rev = E[G[v][i]^1];
            if(e.cap>0 && level[v] <level[e.to]){
                int a = dfs(e.to,t,min(f,e.cap));
                if(a > 0){e.cap -=a ; rev.cap += a;return a;}
            }
        }
        return 0;
    }
    int max_flow(int s,int t){
        int flow = 0;
        for(;;){
            bfs(s);
            if(level[t] < 0 )break;
            ms(cur,0);
            int f;
            while ((f = dfs(s,t,INF)) > 0)flow += f;
        }
        return flow;
    }
}
using namespace dinic;
int totflow[MAX_V];
int low[MAX_E];
int main(int argc, char const *argv[]) {
    int T;
    scanf("%d",&T);
    while (T--) {
        ne =0;
        ms(totflow,0);
        scanf("%d%d",&n,&m);
        s = 0;t = n+1;
        for(int i=0 ; i<m ; ++i){
            int u,v,c;
            scanf("%d%d%d%d",&u,&v,&low[i],&c);
            add_edge(u,v,c-low[i]);totflow[u] -=low[i];totflow[v] += low[i];
        }
        int sum=0;
        for(int i=1 ; i<=n ; ++i)
            if(totflow[i]>0)add_edge(s,i,totflow[i]),sum += totflow[i];
            else add_edge(i,t,-totflow[i]);
        if(max_flow(s,t) == sum){
            printf("YES\n");
            for(int i=1 ; i<2*m ; i+=2)printf("%d\n",low[(i>>1)]+ E[i].cap);
        }else printf("NO\n");
        for(int i=s ; i<=t ; ++i)G[i].clear();
    }
    return 0;
}

有源汇上下界可行流.

只需连一条  ts 容量无限的边就是 上面的模型了.

建图

  1. u->v upper-lower 在源边上建容量上限为 upper-lower的边
  2. 计算每条边的 totflow[u]=in[u]out[u]
  3. 建新的原点,汇点  ss,tt
  4. 对于每个点  totflow[u]>0,ss>u,totflow[u] ,反之建  i>tt,totflow[i]
  5. 跑  sstt 最大流,判断是否可行,

 这个是下面两个的基础

有源汇上下界最大流

建图

  1. 同上.先求可行流设为  f=E[ts].flow (残量网络中的容量)
  2. 将新边( ts,inf )中  st 的容量设为0, 这就等价于上面那片blog 说的重新重  st 增广. 得出最大流  f , f+f 为实际最大流,
    不过对于我的模板来说,其实不必有第一步,因为我们只需在  sstt 的残量网络上直接增广就行因此可以 直接求  st 的最大流

loj 116

#include <bits/stdc++.h>
using namespace std;
#define ms(x,v) (memset((x),(v),sizeof(x)))
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define INF 0x3f3f3f3f
typedef long long LL;
typedef pair<int,int > Pair;
const int MAX_V = 300;
const int MAX_E = 1e5+10;
int n,m;

namespace dinic{
    int ne =0,s,t;
    struct Edge{
        int from ,to,cap;
        Edge(int u=0,int v=0,int c =0):from(u),to(v),cap(c){};
    } E[MAX_E<<2];
    std::vector<int> G[MAX_V];
    int level[MAX_V],cur[MAX_V];
    inline void add_edge(int u,int v,int cap) {
        E[ne] = Edge(u,v,cap);G[u].pb(ne++);
        E[ne] = Edge(v,u,0); G[v].pb(ne++);
    }
    void bfs(int s) {
        ms(level,-1);
        queue<int > Q;Q.push(s);
        level[s] =0;
        while (!Q.empty()) {
            int u = Q.front();Q.pop();
            for(int i=0 ; i< G[u].size() ; ++i){
                Edge &e = E[G[u][i]];
                if(e.cap >0 && level[e.to] <0){level[e.to] = level[u]+1 ; Q.push(e.to);}
            }
        }
    }
    int dfs(int v,int t,int f){
        if(v ==t || f==0)return f;
        for(int &i = cur[v] ; i<G[v].size() ; ++i){
            Edge & e = E[G[v][i]];Edge & rev = E[G[v][i]^1];
            if(e.cap>0 && level[v] <level[e.to]){
                int a = dfs(e.to,t,min(f,e.cap));
                if(a > 0){e.cap -=a ; rev.cap += a;return a;}
            }
        }
        return 0;
    }
    int max_flow(int s,int t){
        int flow = 0;
        for(;;){
            bfs(s);
            if(level[t] < 0 )break;
            ms(cur,0);
            int f;
            while ((f = dfs(s,t,INF)) > 0)flow += f;
        }
        return flow;
    }
}
using namespace dinic;
int totflow[MAX_V];
int low[MAX_E];
int main(int argc, char const *argv[]) {
    scanf("%d%d%d%d",&n,&m,&s,&t );
    for(int i=0 ; i<m ; ++i){
        int u,v,l,up;
        scanf("%d%d%d%d",&u,&v,&l,&up );
        add_edge(u,v,up-l);
        totflow[u]-=l;totflow[v] += l;low[i] = l;
    }
    int sum =0;
    int ss = 0,tt = n+1;
    for(int i=1 ; i<=n ; ++i)
        if(totflow[i]>0)add_edge(ss,i,totflow[i]),sum+=totflow[i];
        else add_edge(i,tt,-totflow[i]);
    add_edge(t,s,INF);
    if(max_flow(ss,tt) == sum){
        int f = E[ne-1].cap;
        E[ne-1].cap =0;
        printf("%d\n",f+ max_flow(s,t));
        //or printf("%d\n",max_flow(s,t));
    }else printf("please go home to sleep\n");
    return 0;
}

有源汇上下界最小流

建图

  1. 同上,先求可行流,求出流量  f=E[ts].flow
  2. ts 的容量设为0 重跑 f=max_flow(t,s) 表示回退流量,最小流为  ff

loj 117

#include <bits/stdc++.h>
using namespace std;
#define ms(x,v) (memset((x),(v),sizeof(x)))
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define INF 0x3f3f3f3f
typedef long long LL;
typedef pair<int,int > Pair;
const int MAX_V = 50000+100;
const int MAX_E = 125000+10;
int n,m;
typedef LL cap_type;
namespace dinic{
    int ne =0,s,t;
    struct Edge{
        int from ,to;
        cap_type cap;
        Edge(int u=0,int v=0,cap_type c =0):from(u),to(v),cap(c){};
    } E[MAX_E<<2];
    std::vector<int> G[MAX_V];
    int level[MAX_V],cur[MAX_V];
    inline void add_edge(int u,int v,cap_type cap) {
        E[ne] = Edge(u,v,cap);G[u].pb(ne++);
        E[ne] = Edge(v,u,0); G[v].pb(ne++);
    }
    void bfs(int s) {
        ms(level,-1);
        queue<int > Q;Q.push(s);
        level[s] =0;
        while (!Q.empty()) {
            int u = Q.front();Q.pop();
            for(int i=0 ; i< G[u].size() ; ++i){
                Edge &e = E[G[u][i]];
                if(e.cap >0 && level[e.to] <0){level[e.to] = level[u]+1 ; Q.push(e.to);}
            }
        }
    }
    cap_type dfs(int v,int t,cap_type f){
        if(v ==t || f==0)return f;
        for(int &i = cur[v] ; i<G[v].size() ; ++i){
            Edge & e = E[G[v][i]];Edge & rev = E[G[v][i]^1];
            if(e.cap>0 && level[v] <level[e.to]){
                int a = dfs(e.to,t,min(f,e.cap));
                if(a > 0){e.cap -=a ; rev.cap += a;return a;}
            }
        }
        return 0;
    }
    cap_type max_flow(int s,int t){
        cap_type flow = 0;
        for(;;){
            bfs(s);
            if(level[t] < 0 )break;
            ms(cur,0);
            cap_type f;
            while ((f = dfs(s,t,INF)) > 0)flow += f;
        }
        return flow;
    }
}
using namespace dinic;
int totflow[MAX_V];
int low[MAX_E];
int main(int argc, char const *argv[]) {
    scanf("%d%d%d%d",&n,&m,&s,&t );
    for(int i=0 ; i<m ; ++i){
        int u,v,l,up;
        scanf("%d%d%d%d",&u,&v,&l,&up );
        add_edge(u,v,up-l);
        totflow[u]-=l;totflow[v] += l;low[i] = l;
    }
    int sum =0;
    int ss = 0,tt = n+1;
    for(int i=1 ; i<=n ; ++i)
        if(totflow[i]>0)add_edge(ss,i,totflow[i]),sum+=totflow[i];
        else add_edge(i,tt,-totflow[i]);
    add_edge(t,s,0x7ffffffffff);
    if(max_flow(ss,tt) == sum){
        //std::cout << E[ne].cap << " " << E[ne-2].cap << '\n';
        cap_type f = E[ne-1].cap;
        E[ne-1].cap = 0;
        printf("%lld\n",f - max_flow(t,s));
    }else printf("please go home to sleep\n");
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值