八、单源点最短路问题

1.问题背景

给定一个带权重的有向图$G=\langle V,E \rangle$和权重函数$\omega:E\rightarrow R$。图中一条路径$p$的权重$\omega(p)$是构成该路径的所有边的权重之和。从结点$u$到结点$v$的最短路径权重定义为$\delta(u,v)$,当没有从$u$到$v$的路径时,$\delta(u,v)=\infty$。

试找出从给定的源点$s\in V$到其他每个结点$v\in V$的最短路径及其最短路径。

  • 单源点最短路问题(单目的地最短路径问题,单节点对最短路径问题),所有结点对最短路径问题

  • 最优子结构性质:两个结点之间的最短路径的任何子路径都是最短的。

  • 松弛操作

    • 对于每个结点$v$,维持一个属性$v.d$,记录从源点$s$到结点$v$的最短路径权重的上界,称$v.d$为$s$到$v$的最短路径估计
    • $INITIALIZE-SINGLE-SOURCE$过程中,对所有$v\in V-{s}$有,$v.d=\infty$,$s.d=0$
    • 松弛操作中,首先进行测试(对$s$到$v$所经过的最后一个中间结点$u$,比较$v.d$和$u.d+w(u,v)$的值),如果可以改善,则更新$v.d$和$v.\pi$
    • 时间复杂度为$O(1)$
  • 松弛操作的性质

    三角不等式性质:$\delta(s,v)\leq\delta(s,u)+\omega(u,v)$

    上界性质:$v.d$是$s$到$v$的最短路径权重$\delta(s,v)$的上界

    非路径性质:假定从源结点$s$到给定点$v$之间不存在路径,则该图在由算法$INITIALIZE-SINGLE-SOURCE(G,s)$进行初始化后,有$v.d\geq \delta(s,v)=\infty$, 并且该等式作为不变式一直维持到图$G$的所有松弛操作结束。

  • 若源点$s$无可达负环,则存在源点$s$的单源最短路径(如果有可达负环,则总有更小距离,最终可以松弛到$-\infty$)

2.$Bellman-Ford$算法

  • 给定带权图$G=\langle V,E,W \rangle$和源点编号$s$,找到源点$s$到所有其他顶点$t$的最短距离$\delta(s,t)$和最短路径$\langle s,\dots,t \rangle$或存在源点$s$可达的负环。

  • 解决挑战1:图中存在负权边时,如何求解单源最短路径?

    • 每轮对所有边进行松弛,持续迭代$\vert V\vert -1$轮。
  • 解决挑战2:图中存在负权边时,如何发现源点可达负环?

    • 若第$\vert V\vert$轮仍松弛成功,存在源点$s$可达的负环。
  • 伪代码如下

    第1行对所有结点的值进行初始化——$\Theta(V)$;

    第$2\thicksim 4$行对每条边进行$\vert V\vert -1$次松弛处理,每次循环中都对每条边进行一次松弛操作——$\Theta(E)$,共进行$\vert V\vert -1$次循环,总的时间复杂度为$\Theta(VE)$;

    第$5\thicksim 8$行检查图中是否存在权重为负值的环路并返回检查结果——$O(E)$;

    总的运行时间为$O(VE)$

  • 证明在无可达负环的情况下可以正确计算最短路径权重

    设$G=\langle V,E \rangle$为一个带权重的源点为$s$的有向图,其权重函数为$\omega:E\rightarrow R$,并假定图$G$中不包含从源结点$s$可以到达的权重为负值的环路。则$Bellman-ford$算法的第$2\thicksim 4$行的$for$循环在执行$\vert V\vert -1$次 之后,对于所有从源结点$s$可以到达的结点$v$有$v.d=\delta(s,v)$。

    证明:利用路径松弛性质

    设$G=\langle V,E \rangle$为一个带权重的源点为$s$的有向图,其权重函数为$\omega:E\rightarrow R$,并假定图$G$中不包含从源结点$s$可以到达的权重为负值的环路。则对于所有结点$v\in V$,存在一条从源结点$s$到结点$v$的路径当且仅当$BELLMAN-FORD$算法终止时有$v.d<\infty$。

  • 证明在有可达负环的情况下可以返回FALSE值,否则返回TRUE值

    假设不包含可达负环时,可以得到$G_\pi$为一棵最短路径树,则当算法终止时,对于所有边$(u,v)\in E$,有$v.d=\delta(s,v)\leq \delta(s,u)+\omega(u,v)=u.d+\omega(u,v)$,因此返回TRUE;

    假设包含可达负环时,设该环路为$c=\langle v_0,v_1,\dots,v_k \rangle$,其中$v_0=v_k$,则有$\sum\limits_{i=1}^{k}\omega(v_{i-1},v_i)<0$,假设返回TRUE值,则有$v_i.d\leq v_{i-1}.d+\omega(v_{i-1},v_i)$,这里$i=1,2,\dots,k$。将所有不等式相加得到$\sum\limits_{i=1}^{k}v_i.d\leq \sum\limits_{i=1}^{k}(v_{i-1}.d+\omega(v_{i-1},v_i))=\sum\limits_{i=1}^{k}v_{i-1}.d+\sum\limits_{i=1}^{k}\omega(v_{i-1},v_i)$,而$v_0=v_k$,则得到$\sum\limits_{i=1}^{k}v_i.d=\sum\limits_{i=1}^{k}v_{i-1}.d$,又有$\sum\limits_{i=1}^{k}\omega(v_{i-1},v_i)\geq 0$,二者矛盾,得证。

3.$Dijkstra$算法

  • 给定带权图$G=\langle V,E,W \rangle$(所有边的权重为正值)和源点编号$s$,找到源点$s$到所有其他顶点$t$的最短距离$\delta(s,t)$和最短路径$\langle s,\dots,t\rangle$。

  • 算法从结点集$V-S$中选择当前最短路径估计最小的结点$u$,将$u$从$Q$中删除,并加入到$S$中,$u.d$就是源结点$s$到$u$的最短路径的 长度。这里$Q$是一个最小优先队列,保存结点集$V-S$。

  • 伪代码如下:

    $while$循环执行次数为$\vert V\vert$次,$for$循环执行$\vert E\vert$次(也即松弛操作次数)。

  • 证明算法的正确性

    采用反证法,假设顶点$u$被添加到$V_A$时,$u.d\ne \delta(s,u)$,而由上界性质有$u.d> \delta(s,u)$。

    应存在一条长度为$\delta(s,u)$的最短路径,设最短路径为$<s,\dots,x,y,\dots,u>$,其中$(x,y)$横跨割$\langle S,V-S\rangle$,$x\in S$,$y\in V-S$;将$x$加入$S$时,有$x.d=\delta(s,x)$,因此$(x,y)$将被松弛,由于$y$是最短路径$p$上的结点,因此有$\delta(s,y)=\delta(s,x)+\omega(x,y)=x.d+\omega(x,y)$,$y.d\leq x.d+\omega(x,y)$,得到$y.d=\delta(s,y)$,因此有$u.d>\delta(s,u)\geq \delta(s,y)=y.d$,显然$u$不是下一个被添加结点,矛盾,得证。

  • 时间复杂度分析:总运行时间依赖于$Q$的实现,采用二叉堆实现时,每次找到结点$u$需要$O(\lg V)$的时间,总运行时间为$O((V+E)\lg V)$

4.算法对比

项目 广度优先搜索 Dijkstra算法 Bellman-Ford算法
适用范围 无权图 带权图(所有边权重为正) 带权图
松弛次数 —— $\vert E \vert$次 $\vert V\vert\cdot\vert E\vert$次
数据结构 队列 优先队列 ——
运行时间 $O(\vert V\vert +\vert E\vert)$ $O(\vert E\vert\cdot\log\vert V\vert)$ $O(\vert E\vert\cdot\vert V\vert)$

5.差分约束系统

  • 线性规划:给定一个$m\times m$的矩阵$A$、一个$m$维的向量$b$和一个$n$维的向量$c$。试找一$n$维向量$x$,使得在$Ax\leq b$的约束下,目标函数$\sum\limits_{i=1}^{n}{c_ix_i}$最大。

  • 差分约束系统:矩阵$A$的每一行包括一个1和一个-1,其他所有项均为0。则上述问题转化为$m$个涉及$n$个变量的差额限制条件,每个约束条件均为简单的线性不等关系:$x_j-x_i\leq b_k$,这里$1\leq i,j\leq n,i\ne j,1\leq k\leq m$。

  • 解的线性性

    $x=(x_1,x_2,\dots,x_n)$为解,则$x+d=(x_1+d,x_2+d,\dots,x_n+d)$也为解;

  • 约束图

    引入额外结点$v_0$,从其出发可到达任何结点,因此节点集合$V$为${v_0,v_1,\dots,v_n}$

    边集合$E$包含代表每个差分约束的边,同时包含$v_0$到其他所有结点的边$(v_0,v_i)$

    如果$x_j-x_i\leq b_k$是一个差分约束条件,则边$(v_i,v_j)$的权重记为$\omega(v_i,v_j)=b_k$,而从$v_0$出发到其他结点的边的权重$\omega(v_0,v_j)=0$。

  • 问题的转换

给定差分约束系统$Ax\leq b$,设$G=\langle V,E \rangle$是该差分约束系统所对应的约束图。如果图$G$不包含权重为负值的回路,则$x=(\delta(v_0,v_1),\delta(v_0,v_2),\delta(v_0,v_3),\dots,\delta(v_0,v_n))$是该系统的一个可行解。如果图$G$包含权重为负值的回路,则该系统没有可行解。

设未知变量的个数$n=\vert x_i\vert$,不等式个数为$m$。则使用$Bellman-Ford$算法时,顶点数为$n+1$,边数为$m+n$,因此可以在$O(n^2+mn)$的时间内完成求解。

九、所有结点对的最短路径问题

1.问题背景

给定一个带权重的有向图$G=\langle V,E \rangle$和权重函数$\omega:E\rightarrow R$。图中一条路径$p$的权重$\omega(p)$是构成该路径的所有边的权重之和。从结点$u$到结点$v$的最短路径权重定义为$\delta(u,v)$,当没有从$u$到$v$的路径时,$\delta(u,v)=\infty$。

求$\forall u,v\in V$,从$u$到$v$的最短路径。

2.问题分析

  • 直观上,可以使用$Dijkstra$算法依次求解所有点,此时存在重叠子问题;

  • 使用$Dijkstra$算法依次求解所有点的算法复杂度为$O(\vert V\vert\vert E\vert\log\vert V\vert)$,对于稠密图有$\vert E\vert=O(\vert V\vert^2)$,因此算法复杂度为$O(\vert V\vert^3\log\vert V\vert)$;

  • 而观察松弛过程发现,具有最优子结构性:

  • 设$D[k,i,j]$表示:可从前$k$个点选点经过时,$i$到$j$的最短距离,则原始问题为$D[\vert V\vert,i,j]$

    如果不选第$k$个点经过,则$D[k,i,j]=D[k-1,i,j]$;

    如果选则第$k$个点经过,则$D[k,i,j]=D[k-1,i,k]+D[k-1,k,j]$;

    因此,$D[k,i,j]=min{D[k-1,i,k]+D[k-1,k,j],D[k-1,i,j]}$

3.自底向上的$Floyd-Warshall$算法

  • 初始化数组

    • $D[0,i,i]=0$:起点和终点重合,路径长度为0
    • $D[0,i,j]=e[i,j]$:任意两点直达距离为边权
  • 自底向上计算

    • 按$k$增加的顺序计算,求解时当前层只依赖上一层
    • 只需要两层表格——待计算和上一次结果
    • 当$k=i$或$k=j$时,$D[k,i,j]=D[k-1,i,j]$,可以直接覆盖;
    • 当$k\ne i且k\ne j$时,$D[k-1,i,k]+D[k-1,k,j]$和$D[k-1,i,j]$不是相同子问题,当求出$D[k,i,j]$后,$D[k-1,i,j]$不再被使用,可直接覆盖——求出新值可直接在原位置覆盖,只需存储一层表格
  • 构建最优解

    • 使用前驱结点矩阵记录经过的中间点,此处使用追踪数组$Rec$记录经过的中间点

      $D_k[i,j]=D_{k-1}[i,j]$时$Rec$记录为0,表示没有中间点

      $D[k,i,j]=D[k-1,i,k]+D[k-1,k,j]$时$Rec$记录为$k$,表示经过中间点$k$

  • 伪代码如下:

    $All-Pairs-Shortest-Paths$:

    初始化数组$D$和$Rec$;

    按照$k$增大的顺序,对于任意一对$i,j$,进行松弛操作,并更新相关数组。

    $Find-Path$:

  • 算法复杂度为$O(\vert V\vert^3)$

4.最短路径算法小结

十、最大流

1.最大二分匹配

(1)问题描述

  • 给定一个无向图$G=\langle V,E \rangle$,其中$V=L\cup R,L\cap R=\Phi$,并且每条边$e\in E$有一个端点在$L$中而另一个端点在$R$中,可记为二分图$G=\langle L,R,E \rangle$。

  • 图$G=\langle V,E \rangle$中的一个匹配$M$是图$G$边集$E$的子集$(M\subseteq E)$,其中每个顶点至多关联$M$的一条边。

  • 现给定二分图$G=\langle L,R,E \rangle$,求出匹配$M={e_1,e_2,\dots,e_k}$,使得$max\vert M\vert$,满足$\forall i,j(i\ne j),e_i=(l_i,r_i),e_j=(l_j,r_j)$,有$l_i\ne l_j$且$r_i\ne r_j$。

    即使得匹配数最大且每个顶点至多关联一条边。

(2)问题分析

  • 直观上,可以遍历$L$中的顶点,依次检查之并与$R$中顶点进行匹配,这种策略可能达不到最大匹配,需要通过撤销边和连接边来增广原匹配。

  • 定义交替路径:从未匹配顶点出发,依次经过“非匹配边、匹配边…非匹配边”**形成的路径

  • 不断寻找交替路径进行增广

    • 依次检测左侧顶点,若相邻顶点未匹配,则构成交替路径,直接进行匹配;若相邻顶点已经匹配,则尝试寻找交替路径,增广成新匹配
    • 直至所有左侧顶点检测完后结束。
  • 辅助数组

    • $matched$表示$L$与$R$中顶点的匹配关系

      以$R$中顶点作为下标,如$match[R_2]\leftarrow L_1$

    • $color$表示深度优先搜索辅助数组

      • white表示未被搜索过,black已被搜索过
      • 每次搜索前初始化$color$数组

(3)匈牙利算法

  • 伪代码如下:

    $Hungarian(G)$

    $DFS-Find(v)$

  • 正确性证明:

    • 命题1:匈牙利算法得到的匹配$M$无交替路径
    • 命题2:匹配$M$无交替路径$\Leftrightarrow$匹配$M$是最大匹配

2.最大流算法

(1)问题描述

  • 给定有向图$G=\langle V,E,C\rangle$,称之为流网络,$C$代表边权。

    • 源点为$s$,汇点为$t$

    • 容量:每条边的边权$c(e)\geq 0$

    • 流量:每条边的被占有容量$f(e)\geq 0$

    • 剩余容量:对于每条边,剩余容量为$c(e)-f(e)$

    • 总流量=源点流出量=汇点流入量:$\vert f\vert=\sum_{e\ out\ of\ s}f(e)=\sum_{e\ in\ to\ t}f(e)$

    • 容量限制:对于边$e\in E$,有$0\leq f(e)\leq c(e)$

      边上的流量不应超过边上的容量

    • 流量守恒:对顶点$v\in V-{s,t}$,$\sum_{e\ out\ of\ s}f(e)=\sum_{e\ in\ to\ t}f(e)$

      进入某顶点$v$流量和等于流出此顶点流量和

  • 现根据有向图$G=\langle V,E,C\rangle$,源点$s$,汇点$t$,在满足容量限制和流量守恒的约束条件下,求出最大流量。

(2)直观策略

  • 算法思想

    • 对于所有边$e\in E$,初始化流量为$f(e)=0$
    • 寻找一条$s$到$t$的路径$P$,此路径上每条边$e$均满足$f(e)<c(e)$
    • 按路径$P$上的最小剩余容量增加路径流量
    • 迭代寻找路径$P$直至无法增加路径流量
  • 此方法可能无法达到最大流量

  • 不足之处:只能扩充边的流量,不能缩减边的流量

  • 如果允许缩减边上的容量 ,则可以进一步增大总流量$\rightarrow$如果寻找路径时允许逆向搜索,可以增大总流量$\rightarrow$引入反向边,实现逆向搜索

  • 残存网络

    • 定义反向边权重:可缩减流量的上限,也即原始边上的流量$f(e)$

    • 定义正向边权重:可扩充流量的上限,也即原始边上的剩余容量$c(e)-f(e)$

    • 则根据流网络$G=\langle V,E,C\rangle$和流量$f$,可得残存网络$G_f=\langle V,E_f\rangle$,其中每条边的残存容量满足上述规则

    • 定义增广路径:增广路径$p$是残存网络$G_f$中一条从源点$s$到汇点$t$的简单路径(路径上的各顶点均不互相重复)

    • 定义增广路径的残存容量:路径上各边残存容量的最小值

      流量扩充的最大值为增广路径的残存容量

(3)$Ford-Fulkerson$算法

  • 算法思想
    • 对于所有边$e\in E$,初始化流量为$f(e)=0$
    • 构造残存网络$G_f$,寻找$s$到$t$的增广路径$P$
    • 按路径$P$的残存容量增加路径流量
    • 迭代寻找路径$P$直至无法增加路径流量
  • 伪代码如下
  • 算法复杂度
  • 正确性证明
    • 充分性:$f$是最大流$\Rightarrow$残存网络$G_f$中无增广路径
    • 必要性:$f$是最大流$\Leftarrow$残存网络$G_f$中无增广路径