算法导论22.1 Exercises 答案
22.1-1
第一个问题的迭代过程如下:
$\begin{array}{|l|l|l|}\hline
v&d&\pi\\hline
s&\infty&\text{NIL}\\hline
t&\infty&\text{NIL}\\hline
x&\infty&\text{NIL}\\hline
y&\infty&\text{NIL}\\hline
z&0&\text{NIL}\\hline
\end{array}
\longrightarrow
\begin{array}{|l|l|l|}\hline
v&d&\pi\\hline
s&2&z\\hline
t&\infty&\text{NIL}\\hline
x&7&z\\hline
y&\infty&\text{NIL}\\hline
z&0&\text{NIL}\\hline
\end{array}
\longrightarrow
\begin{array}{|l|l|l|}\hline
v&d&\pi\\hline
s&2&z\\hline
t&5&x\\hline
x&7&z\\hline
y&9&s\\hline
z&0&\text{NIL}\\hline
\end{array}
\longrightarrow
\begin{array}{|l|l|l|}\hline
v&d&\pi\\hline
s&2&z\\hline
t&5&x\\hline
x&6&y\\hline
y&9&s\\hline
z&0&\text{NIL}\\hline
\end{array}
\longrightarrow
\begin{array}{|l|l|l|}\hline
v&d&\pi\\hline
s&2&z\\hline
t&4&x\\hline
x&6&y\\hline
y&9&s\\hline
z&0&\text{NIL}\\hline
\end{array}$
第二个问题的迭代过程如下:
$\begin{array}{|l|l|l|}\hline
v&d&\pi\\hline
s&0&\text{NIL}\\hline
t&\infty&\text{NIL}\\hline
x&\infty&\text{NIL}\\hline
y&\infty&\text{NIL}\\hline
z&\infty&\text{NIL}\\hline
\end{array}
\longrightarrow
\begin{array}{|l|l|l|}\hline
v&d&\pi\\hline
s&0&\text{NIL}\\hline
t&6&s\\hline
x&\infty&\text{NIL}\\hline
y&7&s\\hline
z&\infty&\text{NIL}\\hline
\end{array}
\longrightarrow
\begin{array}{|l|l|l|}\hline
v&d&\pi\\hline
s&0&\text{NIL}\\hline
t&6&s\\hline
x&4&y\\hline
y&7&s\\hline
z&2&t\\hline
\end{array}
\longrightarrow
\begin{array}{|l|l|l|}\hline
v&d&\pi\\hline
s&0&\text{NIL}\\hline
t&2&x\\hline
x&4&y\\hline
y&7&s\\hline
z&2&t\\hline
\end{array}
\longrightarrow
\begin{array}{|l|l|l|}\hline
v&d&\pi\\hline
s&0&\text{NIL}\\hline
t&2&s\\hline
x&4&y\\hline
y&7&s\\hline
z&-2&t\\hline
\end{array}$
注意到第二个问题中的图有负环,算法BELLMAN-FORD将会返回FALSE。
22.1-2
充分性:根据引理22.2,执行完Bellman-ford算法后,有$v.d=\delta(s,v)。$由于从$s$到$v$中存在路径,那么必定存在一条最短路径,使得$\delta(s,v)<\infty$,因此有$v.d<\infty$。
必要性:由于$v.d<\infty$,这说明节点$v$被松驰过,并且节点的$\pi$属性记录着这条路径的上一个节点。那么我们可以递归访问路径上其前驱节点。由于其前驱子图$G_\pi$是一棵以$s$为根的树,因此我们最终可以递归访问到$s$节点,这说明从$s$到$v$存在一条路径。
22.1-3
如果所有边都不再被松弛,那么说明整个算法可以结束了。因此我们使用一个布尔遍历来记录第$i$轮迭代是否发生了松弛,如果没有发生松弛那么可以及时结束整个算法。改进后的程序为BELLMAN-FORD':
1 | RELAX'(u, v, w) |
22.1-4
如果在第$|V|$轮迭代中,一条边$(u,v)$仍然进行了一次松弛操作,那么说明$v$存在于某个负环中。这说明,从$v$开始可达的节点,都不存在最短路径。因此我们标记上这些节点,然后通过DFS访问这些节点所有的可达节点,并将它们标记上$-\infty$即可。这个算法由BELLMAN-FORD''给出,其时间复杂度仍然为$O(V^2+VE)$,因为标记节点所需要的开销远远低于BELLMAN-FORD算法本身的执行过程。
1 |
|
22.1-5
如果边集$E$是直接按照一个列表给定的,那么就不必再在每次迭代中遍历每个节点,再访问其对应的边。直接访问这个列表中的边进行松弛操作即可,把时间复杂度从$O(V^2+VE)$降到$O(VE)$,这在图非常稀疏时是有效的,这个算法由程序BELLMAN-FORD'''给出。
1 | BELLMAN-FORD'''(G, s) |
22.1-6
也就是说,$\delta^{\ast}(v)$是图$G=(V,E)$中,$V$中所有节点到$v$的最短距离。那么所有节点的$v.d$的初始化值为$0$,因为初始化时$d=0$意味着从其它节点到自身距离当前的最小值。整个算法由程序CAL-DELTA-STAR给出,除了初始化步骤不相同,其它步骤都一样,此外还使用了题目22.1-4中的子程序DFS-VISIT-BELLMAN-FORD用来填充$-\infty$。因此最终其时间复杂度为$O(VE)$。
1 | CAL-DELTA-STAR(G, w) |
另外一个看待这一道题目的角度是,构造一个超级原点$s$,令$G’=\left(V\cup{s},E\cup\bigcup_{v\in V}(s,v)\right)$。并且$\forall v\in V,w(s,v)=0$。那么我们可以对超级原点$s$进行Bellman-Ford算法。其结果和程序CAL-DELTA-STAR一致。因为$s$相当于是将$V$中的所有节点集合在一起,形成一个新的起点。
22.1-7
进行完$|V|-1$轮的松弛操作后,如果仍然发现有$v.d > u.d + w(u, v)$,那么说明点$v$必定出现在了某一个负环$C$中。事实上,由于负环中的每条边都进行了反复松弛,那么$v$的前驱节点$v.\pi$也会在$C$中。迭代访问$v$的$\pi$属性,最终可以将一个整个环$C$处理出来。
整个算法由过程GET-NEG-CYCLE给出,与过程BELLMAN-FORD类似,其时间复杂度为$O(V^2+VE)$。
1 | GET-NEG-CYCLE(G, w, s) |