网络流 __4 上下界可行流

对于容量有上下界规范的网络流问题

无源汇上下界可行流

n个点m条边的有向图,每条边有一个流量下界和流量上界规范,求是否存在一个可行流

设原网络为(G,F),变换后网络为(G',S'),每条边上界Cl(u,v),下界Cu(u,v),流量f(u,v).对于上下界,我们很容易将等式变形:
c l ( u , v ) ≤ f ( u , v ) ≤ c u ( u , v ) → 0 ≤ f ( u , v ) − c l ( u , v ) ≤ c u ( u , v ) − c l ( u , v ) c_l(u,v) \le f(u,v) \le c_u(u,v) \to 0 \le f(u,v) - c_l(u,v)\le c_u(u,v) -c_l(u,v) cl​(u,v)≤f(u,v)≤cu​(u,v)→0≤f(u,v)−cl​(u,v)≤cu​(u,v)−cl​(u,v)
考察变形之后的网络,满足容量限制,但是并不满足流量守恒,原因:

对于一个有向图G

考察图上P点:

变 换 前 : f ( v 1 , p ) + f ( v 2 , p ) = f ( p , v 3 ) 变换前: f(v1,p) + f(v2,p) = f(p,v3) 变换前:f(v1,p)+f(v2,p)=f(p,v3)

变 换 后 : ( f ( v 1 , p ) − c ) + ( f ( v 2 , p ) − c ) ≠ f ( p , v 3 ) − c 变换后: (f(v1,p) - c) + (f(v2,p) - c) \neq f(p,v3) - c 变换后:(f(v1,p)−c)+(f(v2,p)−c)​=f(p,v3)−c

因此我们需要进行构造来使得变换后的仍为一个流网络

  • 构造方法:(此处略与y总不同,但是更好理解)

C入:进入P点,因变换而减少的流量(相当于进来的补给变少了);C出:从P点出,因变换而增加的流量 (相当于出去的消耗变少了);CC = C出 - C入

对于每一个点,若其C > 0则说明补给减少的量小于消耗减少的量(虽然给我少了,但是我用的更少),说明该点有余量,因此从此点向汇点T连接一条容量为C的边来释放多余的量

C < 0则说明消耗减少的量小于补给减少的量(流出了很多但是流进来很少),说明该点缺少流量,因此需要从源点S流入C的流量才能满足流出的流量。因此从源点S向此点连接一条容量为C的边来补充缺少的量

注意:此时可以发现对于任意P点,若S与之相连,那条边是满流的,之若与T相连,那条边也是满流(因为构造就是这么构造的),因此形成了一个从源点到汇点的最大流

AC代码

难在建图,建图建好了直接上板子就行

const int N = 510 , M = 2*(11000+N) , INF = 1e8;
int n,m,S,T;
int e[M],ne[M],h[N],f[M],l[M],idx=0;
int cur[M],q[M],d[M],A[M];void add(int a,int b,int c,int d){e[idx] = b , f[idx] = d-c , l[idx] = c , ne[idx] = h[a] , h[a] = idx ++ ;e[idx] = a , f[idx] = 0 , ne[idx] = h[b] , h[b] = idx ++ ;
}bool bfs(){memset(d,-1,sizeof d);int hh = 0 , tt = 0;q[0] = S , cur[S] = h[S] , d[S] = 0;while(hh <= tt){int u = q[hh ++];for(int i = h[u]; ~i ; i = ne[i]){int ver = e[i];if(d[ver] == -1 && f[i]){d[ver] = d[u] + 1;cur[ver] = h[ver];if(ver == T) return true;q[++ tt] = ver;}}}return false;
}int find(int u,int limit){if(u == T) return limit;int flow = 0;for(int i=cur[u];~i && flow < limit;i=ne[i]){cur[u] = i;int ver = e[i];if(d[ver] == d[u] + 1 && f[i]){int t = find(ver,min(f[i],limit-flow));if(t == 0) d[ver] = -1;f[i] -= t , f[i^1] += t , flow += t;}}return flow;
}int dinic(){int ans = 0 , flow = 0;while(bfs()) while(flow = find(S,INF)) ans += flow;return ans;
}
//=================================
int main(){memset(h,-1,sizeof h);n = read() , m = read();S = 0 , T = n + 1;int tot = 0;rep(i,1,m){int a = read() , b = read() , c = read() , d = read();add(a,b,c,d);// tot += d - c; 最大流流量应该与中间怎么流的没有关系A[a] += c , A[b] -= c;  //每有一条出边变换之后会少消耗c(相当于+c),每有一条入边会少补给c(相当于-c)}rep(i,1,n)if(A[i] > 0) add(i,T,0,A[i]) ;//还有余量,因此流向汇点 else if(A[i] < 0 ) add(S,i,0,-A[i]),tot-=A[i]; //缺少补给,因此从源点流入/*y总写法,一样的道理,反过来考虑rep(i,1,m){int a = read() , b = read() , c = read() , d = read();add(a,b,c,d);A[a] -= c , A[b] += c;   //每有一条入边变换之后就能多消耗c,每有一条出边变换之后就能少消耗c}rep(i,1,n)if(A[i] > 0 ) add(S,i,0,A[i]), tot += A[i];else if(A[i] < 0) add(i,T,0,-A[i]);*/if(dinic() != tot) puts("NO");else{puts("YES");for(int i=0;i<2*m;i+=2)//if(e[i] > 0 && e[i] <= n && e[i^1] > 0 && e[i^1] <= n)print(f[i^1] + l[i]);}return 0;
}

有源汇上下界最大流

n个点m条边的有向图,每一条边都有一个流量下界和流量上界,求从源点S到汇点T的最大流

  • 算法:

1.记原来的源点为s,汇点为t,同无源汇的方式,建立虚拟源点S和汇点T,通过式子变形将其转化为一个新图G'
变 换 前 : f ( v 1 , p ) + f ( v 2 , p ) = f ( p , v 3 ) 变换前: f(v1,p) + f(v2,p) = f(p,v3) 变换前:f(v1,p)+f(v2,p)=f(p,v3)

变 换 后 : ( f ( v 1 , p ) − c ) + ( f ( v 2 , p ) − c ) ≠ f ( p , v 3 ) − c 变换后: (f(v1,p) - c) + (f(v2,p) - c) \neq f(p,v3) - c 变换后:(f(v1,p)−c)+(f(v2,p)−c)​=f(p,v3)−c

由于建立新图之后,此时原来的源点s和汇点t会变成中间结点,因此为了使之流量守恒,我们需要从ts连一条容量为正无穷的边。

2.从S向T跑一遍Dinic算法,如果从S出的流量是满流,说明新图存在可行流,即此上下行约束下存在可行流

3.若存在可行流,再原来的源点s到原来的汇点t的跑一遍dinic算法(在残留网络上不断的搞掉增广路径),此时得到的便是s到t的最大流

  • 证明:

    • 证明思路:证明原图中的上下界可行流于新图中的可行流存在一一映射

  • ( G 原 图 , f 0 可 行 上 下 界 可 行 流 ) → ( G ′ 新 图 中 的 可 行 流 , f 0 ′ 新 图 中 的 可 行 流 ( 从 S 出 发 的 满 流 ) ) (G原图,f_0可行上下界可行流) \to (G^{'}新图中的可行流,f^{'}_{0}新图中的可行流(从S出发的满流)) (G原图,f0​可行上下界可行流)→(G′新图中的可行流,f0′​新图中的可行流(从S出发的满流))

    G f 0 ′ ′ 为 f 0 ′ 的 残 留 网 络 , f 0 s → t ′ 为 f 0 ′ 中 的 s → t 的 可 行 流 G^{'}_{f_0^{'}}为f_0^{'}的残留网络,f_{0 s \to t}^{'}为f^{'}_{0}中的s \to t的可行流 Gf0′​′​为f0′​的残留网络,f0s→t′​为f0′​中的s→t的可行流

    证:
    ∣ f 0 s → t ′ + f 0 ′ ∣ 仍 然 是 新 图 上 的 可 行 流 |f_{0 s \to t}^{'}+f_0^{'}| 仍然是新图上的可行流 ∣f0s→t′​+f0′​∣仍然是新图上的可行流
    流量守恒:由S出去的都是满流,进入T的也都是满流,因此对于s -> t的任意可行流都不经过S和T

    容量限制:由于t向s连接了一条容量为无穷的边,因此每一条边都满足容量限制
    f ′ 对 应 一 条 s → t 的 可 行 流 f^{'}对应一条s\to t的可行流 f′对应一条s→t的可行流
    f'-f0'可以构造出所有流量都在中间,因为S、T对于f'f0'而言都是满流 。

    综上,原图中的上下界可行流于新图中的可行流存在一一映射,因此算法X具有正确性

const int INF = 1e8,N=510,M=2*(N+10010);
int n,m,S,T;
int e[M],ne[M],h[N],f[M],idx=0;
int q[M],cur[M],d[M],A[M];void add(int a,int b,int c){e[idx] = b , f[idx] = c , ne[idx] = h[a] , h[a] = idx ++;e[idx] = a , f[idx] = 0 , ne[idx] = h[b] , h[b] = idx ++;
}int find(int u,int limit){if(u == T) return limit;int flow = 0;for(int i=cur[u];~i && flow < limit;i=ne[i]){cur[u] = i;int ver = e[i];if(d[ver] == d[u] + 1 && f[i]){int t = find(ver,min(f[i],limit-flow));if(!t) d[ver] = -1;f[i] -= t , f[i^1] += t , flow += t;}}return flow;
}bool bfs(){memset(d,-1,sizeof d);int hh = 0 , tt = 0;q[0] = S , cur[S] = h[S] , d[S] = 0;while(hh <= tt){int u = q[hh ++];for(int i=h[u];~i;i=ne[i]){int ver = e[i];if(d[ver] == -1 && f[i]){d[ver] = d[u] + 1;cur[ver] = h[ver];if(ver == T) return true;q[++ tt] = ver;}}}return false;
}int dinic(){int ans = 0 , flow = 0;while(bfs()) while(flow = find(S,INF)) ans += flow;return ans;
}
//=================================
int main(){memset(h,-1,sizeof h);int s,t,ans=0;n = read() , m = read() , s = read() , t = read();S = 0 , T = n + 1;rep(i,1,m){int a = read(), b = read() , c = read() , d = read();add(a,b,d-c);A[a] += c ,A[b] -= c;}int tot = 0;rep(i,1,n){if(A[i] > 0) add(i,T,A[i]);else if(A[i] < 0 ) add(S,i,-A[i]),tot-=A[i];}add(t,s,INF);if(dinic() < tot) puts("No Solution");else{ans = f[idx - 1];  //f[idx-2]为容量,因此其反向边f[(idx-2)^1] = f[idx-1]为流量f[idx-1] = f[idx-2] = 0; //删除这两条边S = s , T = t;print(ans+dinic());}return 0;
}

有源汇上下界最小流

有源汇上下界最小流只需要对有源汇上下界最大流进行变形即可,本质相同。

  • 思路:

由有源汇最大流可知,原网络G上任意一可行流f经过变换得到的新网络上可行流f'都可以通过新网络上一条可行流(S出发的满流)f0'f s->t之和得到,即
∣ f ′ ∣ = ∣ f 0 ′ ∣ + ∣ f s → t ∣ |f^{'}| = |f^{'}_0| + |f_{s \to t}| ∣f′∣=∣f0′​∣+∣fs→t​∣
又有
∣ f s → t ∣ = − ∣ f t → s ∣ |f_{s \to t}| = - |f _{t \to s}| ∣fs→t​∣=−∣ft→s​∣
因此,我们可以通过按照无源汇的方式建立好虚拟源点S流入虚拟汇点T流出的流网络。通过dinic算法验证此流网络是否满足S所有出边都是满流来考察新网络是否存在可行流。若存在 ,从原来的汇点t向原来的源点s做一遍dinic算法,从而消除t -> s路径上的所有增广路径以获得t -> s的最大流,由上述公式,t -> s为最大流,则s -> t为最小流,因此最终的答案即为:
a n s = ∣ f 0 ′ ∣ − ∣ f m a x ( t → s ) ∣ ans = |f^{'}_{0}| - |f_{max(t \to s)}| ans=∣f0′​∣−∣fmax(t→s)​∣

代码奉上:
int n,m,S,T;
int e[M],ne[M],f[M],h[N],idx=0;
int q[M],d[N],cur[M],A[N];void add(int a,int b,int c){e[idx] = b , f[idx] = c , ne[idx] = h[a] , h[a] = idx ++;e[idx] = a , f[idx] = 0 , ne[idx] = h[b] , h[b] = idx ++;
}int find(int u,int limit){if(u == T) return limit;int flow = 0;for(int i=cur[u];~i && flow < limit ; i = ne[i]){cur[u] = i;int ver = e[i];if(d[ver] == d[u] + 1 && f[i]){int t = find(ver,min(f[i],limit - flow));if(!t) d[ver] = -1;f[i] -= t , f[i^1] += t , flow += t;}}return flow;
}bool bfs(){memset(d,-1,sizeof d);int hh = 0 , tt = 0;q[0] = S , cur[S] = h[S] , d[S] = 0;while(hh <= tt){int u = q[hh ++];for(int i=h[u];~i;i=ne[i]){int ver = e[i];if(d[ver] == -1 && f[i]){d[ver] = d[u] + 1;cur[ver] = h[ver];if(ver == T) return true;q[++ tt] = ver;}}}return false;
}int dinic(){int ans = 0 , flow = 0;while(bfs()) while(flow = find(S,INF)) ans += flow;return ans;
}
//=================================
int main(){memset(h,-1,sizeof h);int s , t , ans = 0;n = read() , m = read() , s = read() , t = read();S = 0 , T = n + 1;rep(i,1,m){int a = read() , b = read() , c = read() , d = read();add(a,b,d-c);A[a] += c , A[b] -= c;}int tot = 0;rep(i,1,n){if(A[i] > 0 ) add(i,T,A[i]);else if(A[i] < 0) add(S,i,-A[i]) , tot -= A[i];}add(t,s,INF);if(dinic() < tot) puts("No Solution");else{ans = f[idx - 1]; //s向t的流量f[idx - 1] = f[idx - 2] = 0;S = t, T = s;print(ans - dinic());}return 0;
}

网络流__4 上下界可行流相关推荐

  1. 无源汇有上下界可行流(网络流进阶)

    无源汇有上下界可行流(也就是循环流) 模型:一个网络,求出一个流,使得每条边的流量必须>=Li且<=Hi, 每个点必须满足总流入量=总流出量(流量守恒)(这个流的特点是循环往复,无始无终) ...

  2. 一篇网络流 基本模型超全总结(最大流 费用流 多源汇最大流 上下界可行流) 思路+代码模板

    文章目录 一.网络流与最大流 二.网络流三个基本性质 三.重要定义定理 四.最大流算法 <Ⅰ> Edmonds-Karp算法(EK算法) 1.EK算法 2.算法思想: 3.代码模板 4.模 ...

  3. BZOJ 2406 LuoguP4194 矩阵 有上下界可行流

    分析: 这道题乍一看--卧槽这都什么玩意-- 然后发现给了个A矩阵,要求一个可行的B矩阵,使得矩阵C=A-B的每一行的和的绝对值和每一列的和的绝对值的最大值最小-- 好拗口啊-- 什么最大值最小之类的 ...

  4. loj#115. 无源汇有上下界可行流

    \(\color{#0066ff}{ 题目描述 }\) 这是一道模板题. \(n\) 个点,\(m\) 条边,每条边 \(e\) 有一个流量下界 \(\text{lower}(e)\) 和流量上界 \ ...

  5. 【bzoj2406】矩阵 二分+有上下界可行流

    题目描述 输入 第一行两个数n.m,表示矩阵的大小. 接下来n行,每行m列,描述矩阵A. 最后一行两个数L,R. 输出 第一行,输出最小的答案: 样例输入 2 2 0 1 2 1 0 1 样例输出 1 ...

  6. 【ACWing】2188. 无源汇上下界可行流

    题目地址: https://www.acwing.com/problem/content/2190/ 给定一个包含nnn个点mmm条边的有向图,每条边都有一个流量下界和流量上界.求一种可行方案使得在所 ...

  7. 【zoj2314】Reactor Cooling 有上下界可行流

    题目描述 The terrorist group leaded by a well known international terrorist Ben Bladen is buliding a nuc ...

  8. bzoj 2406 矩阵——有源汇上下界可行流

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2406 二分答案.把 b 的 n 个行作为一排, m 个列作为一排,每行和每列之间连上下界为 ...

  9. LOJ116 有源汇有上下界最大流(上下界网络流)

    考虑有源汇上下界可行流:由汇向源连inf边,那么变成无源汇图,按上题做法跑出可行流.此时该inf边的流量即为原图中该可行流的流量.因为可以假装把加上去的那些边的流量放回原图. 此时再从原来的源向原来的 ...

最新文章

  1. MySQL 高级 - 存储过程 - 函数
  2. Python之递归函数
  3. 如何在 jetbrick-template 中使用 debug函数?
  4. SAP Spartacus cx-split-view几个css属性值的逻辑依赖关系
  5. Build Provider 不得不说的事
  6. centos7 卸载 gitlab
  7. 大数据_Hbase-Filter 索引(优化)_根据column查询---Hbase工作笔记0020
  8. 英国汇丰银行拒绝为客户处理加密货币交易
  9. 2021.01.04 第 1 个工作日反思
  10. Android widget开发有感
  11. 黑客无孔不入!网络安全成五角大楼重中之重
  12. win10好用的C语言软件,9款超级实用的Win10软件,一定要收藏,简直不要太好用
  13. ARRI阿莱MXF修复方法
  14. JAVA 工厂模式计算器
  15. 区分BPSK、QPSK、8PSK和区分8QAM、16QAM、32QAM、64QAM
  16. 如何让函数只执行一次
  17. 数字图像处理:空间相关与卷积操作
  18. mysql的配置管理_MySQL 启动流程及配置管理
  19. shell脚本——正则表达式(包含grep详细介绍及应用)
  20. 电脑录音效果不佳的问题解决

热门文章

  1. 易语言编写的Windows XP扫雷推理辅助
  2. 萤石C6语言对话怎么设置,萤石C6使用说明
  3. Excel_日期和时间函数、EDATE、EOMONTH
  4. FreeSurfer的安装和使用
  5. 华为Atlas200DK开发从零开始3.目标检测模型CANN部署——以YOLOX、YOLOv5和Nanodet为例(2)CANN模型的转换,ATC转换工具
  6. 操作无法完成(错误0x00000709)解决方法
  7. Windows系统查询激活状态和时间的办法-Windows许可证即将过期
  8. pandas练习---100题-和鲸kesci版
  9. Java常见面试题汇总(一)
  10. i7 10750h和i5 11260h选哪个