最大流最小割概念及ADT EK算法

最近感冒身体状况奇差,直接走堂了上周的3391,OJ也没怎么看(看了也看不进去看进去也不会),乘着灌了一吨药睡醒后结合紫书和课件,参考其他大佬的博客写完这个方面的概念和ADT吧。

1.概念

最大流定义:从$s$(通常规定为$1$)运东西到$t$(通常规定为$n$),最多运多少的问题称为最大流。关注点主要在边上。对一条边$(u,v)$,$c(u,v)$表示它可以运送物品的上限(capacity),$f(u,v)$表示实际运送的流量(flow)。很容易得到(规定)$f(u,v)=-f(v,u)$(对于不直接连接的两点,肯定有$c(u,v)=f(u,v)=0$)。$c,v$之差称为残量,残量网络是原网络的两倍,反向边的作用是用来返回来找最优解。

(https://www.cnblogs.com/dchipnau/archive/2011/09/16/4985966.html)这篇blog说明了反向边的作用,看完后可以参考该博客

最大流问题的目标是把最多的东西从$s$运到$t$,其他结点都是用来中转的(甚至可以不用)。因此对$s$和$t$以外任意点$u$,到其他所有(相邻)结点$v$的流量有  $\sum\limits_{(u,v)^{}\in E}=0$ (E表示所有edge的集合)(有些$f$是负数)。因为要最多的$s$到$t$,所以,最后到其他任何结点上存在的量为0。(要么经过它最终到$t$,要么压根不经过它)。可以知道最大流的值为$|f|=\sum\limits_{(s,v)\in E}f(s,v)=\sum\limits_{(u,t)\in E}f(u,t)$。

2.增广路算法 Edmonds-Karp

核心思想为BFS,EK算法。

从零流(所有边的流量均为0)开始不断增加流量,保持每次增加流量后都满足容量限制,斜对称性,流量平衡。

\begin{equation}
\left\{
\begin{array}{lr}
f(u,v)<=c(u,v)  \\
f(u,v)=-f(v,u) \\
\forall u!=(s||t), \sum \limits_{(u,v)\in E}f(u,v)=0 
\end{array}
\right.
\end{equation}

算法基于:残量网络中任何一条$s$到$t$的有向道路都对应一条原图中的增广路(可以增加流量的路),只要求出该路中残量最小值$d$,把对应边的流量加上$d$即可。如果残量网络中不存在增广路,则当前流为最大流。

ADT如下:

 1 const int INF = 1000000000;
 2 const int MAXN = 205;
 3 
 4 struct Edge{
 5     int from, to, cap, flow;
 6     Edge(int u, int v, int c, int f):from(u), to(v), cap(c), flow(f){}
 7 };
 8 
 9 struct EK{
10     int n, m;
11     vector<Edge> edges; //残量网络,边数是两倍
12     vector<int> G[MAXN]; //领接表,G[i][j]表示从i点出来的每条边j在edge中的序号,用来记录和i相关(从i出发)的edges
13     int a[MAXN]; //从s出发到每个点的最小残量, a[t]是整条道路上的最小残量
14     int p[MAXN]; //最短路树上p的入弧编号
15     
16     void init(int n){
17         for(int i=0;i<n;i++){
18             G[i].clear();
19         }
20         edges.clear();
21     }
22     
23     void AddEdge(int from, int to, int cap){
24         edges.push_back(Edge(from, to, cap, 0));
25         edges.push_back(Edge(to, from, 0, 0)); //反向弧
26         m = edges.size(); //所以m-1是图中最后加入的一条边的编号
27         G[from].push_back(m-2); //图中倒数第二条加入的边是从from发出去的
28         G[to].push_back(m-1); //edges中最后一条边编号为m-1,从to到from
29     }
30     
31     int MaxFlow(int s, int t){
32         int flow = 0;//一开始判断最大流为0
33         for(;;){
34             memset(a,0,sizeof(a));
35             queue<int> Q;
36             Q.push(s);
37             a[s] = INF; //到自己的残量为INF所以一定会被取代(如果存在)
38             while(!Q.empty()){
39                 int tmp = Q.front();
40                 Q.pop();
41                 for(int i=0;i<G[tmp].size();i++){
42                     Edge& e = edges[G[tmp][i]]; //用地址符是直接对edges进行操作
43                     if(!a[e.to]&&e.cap>e.flow){//存在残量 并且这条路可以走
44                         p[e.to] = G[tmp][i]; //这条路径的终点(global编号)从领接表里面找到
45                         a[e.to] = min(a[tmp], e.cap-e.flow); //残量取小的
46                         Q.push(e.to);
47                     }
48                 }
49                 if(a[t]){
50                     break;
51                 }
52             }
53             if(!a[t]){ //此时一定不能再存在增广路了,直接break节约时间
54                 break;
55             }
56             for(int u=t;u!=s;u=edges[p[u]].from){
57                 edges[p[u]].flow += a[t];
58                 edges[p[u]^1].flow -= a[t]; //这个异或是干啥用的?
59                 //边i的反向边为i^1,^为二进制异或运算符,
60             }
61             flow += a[t];
62 
63         }
64         return flow;
65     }
66 };
View Code

 

 3.最小割最大流定理

最大流的值(流量)等于最小割的容量(容量)。

把所有顶点分成两个集合:$S$和$T$,如果把“起点在$S$中,终点在$T$中”的边全部删除,就无法从$s$到$t$了。这样的集合划分称为一个$s,t$割。它的大小定义为:$c(S,T)=\sum\limits_{u \in S,t \in T}c(u,v)$,即所有起点在$S$,终点在$T$的边的容量和。

可以这样理解:从$s$到$t$,必定通过跨越$S$和$T$的边,所以从$s$到$t$的净流量$|f|=f(S,T)=\sum\limits_{u\in s,v\in T}f(u,v)<=\sum\limits_{u\in S,v\in T}c(u,v)=c(S,T)$(因为可能有的边的容量虽有但是已经到达最大流了无法用掉它的容量(记得EK算法每次找路径上$a$最小值))。

结论:EK算法结束时,($a[u]>0$的结点)集合为$S$,其他为$T$,则$(S,T)$是图的$s-t$最小割。

转载于:https://www.cnblogs.com/cmbyn/p/8601788.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
资源包主要包含以下内容: ASP项目源码:每个资源包中都包含完整的ASP项目源码,这些源码采用了经典的ASP技术开发,结构清晰、注释详细,帮助用户轻松理解整个项目的逻辑和实现方式。通过这些源码,用户可以学习到ASP的基本语法、服务器端脚本编写方法、数据库操作、用户权限管理等关键技术。 数据库设计文件:为了方便用户更好地理解系统的后台逻辑,每个项目中都附带了完整的数据库设计文件。这些文件通常包括数据库结构图、数据表设计文档,以及示例数据SQL脚本。用户可以通过这些文件快速搭建项目所需的数据库环境,并了解各个数据表之间的关系和作用。 详细的开发文档:每个资源包都附有详细的开发文档,文档内容包括项目背景介绍、功能模块说明、系统流程图、用户界面设计以及关键代码解析等。这些文档为用户提供了深入的学习材料,使得即便是从零开始的开发者也能逐步掌握项目开发的全过程。 项目演示与使用指南:为帮助用户更好地理解和使用这些ASP项目,每个资源包中都包含项目的演示文件和使用指南。演示文件通常以视频或图文形式展示项目的主要功能和操作流程,使用指南则详细说明了如何配置开发环境、部署项目以及常见问题的解决方法。 毕业设计参考:对于正在准备毕业设计的学生来说,这些资源包是绝佳的参考材料。每个项目不仅功能完善、结构清晰,还符合常见的毕业设计要和标准。通过这些项目,学生可以学习到如何从零开始构建一个完整的Web系统,并积累丰富的项目经验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值