@@ -49,22 +49,29 @@ import numpy as np
49
49
```
50
50
51
51
## 问题概述
52
- 最短路径问题是寻找如何以最小成本从[ 图] ( https://en.wikipedia.org/wiki/Graph_%28mathematics%29 ) 中的一个指定节点遍历到另一个节点。
52
+
53
+ 最短路径问题是寻找如何以最小成本从[ 图] ( https://baike.baidu.com/item/%E5%9B%BE/13018767 ) 中的一个指定节点遍历到另一个节点。
54
+
53
55
考虑下面这个图
54
56
55
57
``` {figure} /_static/lecture_specific/short_path/graph.png
56
58
57
59
```
58
60
59
61
我们希望以最小成本从节点(顶点)A到达节点G
62
+
60
63
* 箭头(边)表示我们可以采取的移动。
61
64
* 边上的数字表示沿该边行进的成本。
62
65
(像上面这样的图被称为加权[ 有向图] ( https://en.wikipedia.org/wiki/Directed_graph ) 。)
66
+
63
67
图的可能解释包括
68
+
64
69
* 供应商到达目的地的最小成本。
65
70
* 互联网上的数据包路由(最小化时间)。
66
71
* 等等。
72
+
67
73
对于这个简单的图,快速扫描边可以看出最优路径是
74
+
68
75
* A, C, F, G,成本为8
69
76
70
77
``` {figure} /_static/lecture_specific/short_path/graph4.png
@@ -78,16 +85,21 @@ import numpy as np
78
85
```
79
86
80
87
## 寻找最低成本路径
81
- 对于大型图,我们需要一个系统的解决方案。
88
+
89
+ 对于更大的图,我们需要一个系统性的解决方案。
90
+
82
91
让 $J(v)$ 表示从节点 $v$ 出发的最小成本,理解为如果我们选择最佳路线,从 $v$ 出发的总成本。
92
+
83
93
假设我们知道每个节点 $v$ 的 $J(v)$,如下图所示(基于前面示例中的图)。
84
94
85
95
``` {figure} /_static/lecture_specific/short_path/graph2.png
86
96
87
97
```
88
98
89
99
注意 $J(G) = 0$。
90
- 现在可以通过以下步骤找到最佳路径:
100
+
101
+ 我们可以通过以下步骤找到最佳路径:
102
+
91
103
1 . 从节点 $v = A$ 开始
92
104
1 . 从当前节点 $v$,移动到解决以下问题的任何节点
93
105
@@ -98,10 +110,14 @@ import numpy as np
98
110
```
99
111
100
112
其中
113
+
101
114
* $F_v$ 是可以从 $v$ 一步到达的节点集合。
102
115
* $c(v, w)$ 是从 $v$ 到 $w$ 的旅行成本。
103
- 因此,如果我们知道函数 $J$,那么找到最佳路径几乎就是微不足道的事。
116
+ *
117
+ 因此,如果我们知道函数 $J$,那么找到最佳路径几乎就是轻而易举的事。
118
+
104
119
但是我们如何找到成本函数 $J$ 呢?
120
+
105
121
经过一些思考,你会确信对于每个节点 $v$,
106
122
函数 $J$ 满足
107
123
@@ -111,15 +127,15 @@ import numpy as np
111
127
J(v) = \min_{w \in F_v} \{ c(v, w) + J(w) \}
112
128
```
113
129
114
- 这被称为** 贝尔曼方程** ,以数学家[ 理查德·贝尔曼] ( https://en.wikipedia.org/wiki/Richard_E._Bellman ) 的名字命名。
130
+ 这被称为** 贝尔曼方程** ,以数学家[ 理查德·贝尔曼] ( https://baike.baidu.com/item/%E8%B4%9D%E5%B0%94%E6%9B%BC%E6%96%B9%E7%A8%8B/5500990 ) 的名字命名。
115
131
116
132
贝尔曼方程可以被理解为$J$必须满足的一个限制条件。
117
133
118
134
我们现在想要做的是利用这个限制条件来计算$J$。
119
135
120
- ## 求解最小代价-到-目标
136
+ ## 求解最小成本函数
121
137
122
- 让我们来看一个计算 $J$的算法,然后思考如何实现它。
138
+ 让我们一起学习一个计算 $J$的算法,然后思考如何实现它。
123
139
124
140
### 算法
125
141
@@ -139,7 +155,9 @@ J_0(v) = 0 \text{ for all } v
139
155
1 . 设 $n = 0$
140
156
2 . 对所有 $v$,设 $J_ {n+1} (v) = \min_ {w \in F_v} \{ c(v, w) + J_n(w) \} $
141
157
3 . 如果 $J_ {n+1}$ 和 $J_n$ 不相等,则将 $n$ 加 1,返回步骤 2
158
+
142
159
这个序列收敛于 $J$。
160
+
143
161
虽然我们在此省略了证明,但我们将在其他动态规划讲座中证明类似的结论。
144
162
145
163
### 实现
@@ -156,6 +174,7 @@ Q(v, w)
156
174
& +\infty \text{ 否则 }
157
175
\end{cases}
158
176
$$
177
+
159
178
在这种情况下,$Q$ 通常被称为** 距离矩阵** 。
160
179
161
180
我们现在也对节点进行编号,其中 $A = 0$,所以,例如
@@ -165,6 +184,7 @@ Q(1, 2)
165
184
=
166
185
\text{ 从 B 到 C 的旅行成本 }
167
186
$$
187
+
168
188
例如,对于上面的简单图,我们设置
169
189
170
190
``` {code-cell} python3
@@ -180,13 +200,15 @@ Q = np.array([[inf, 1, 5, 3, inf, inf, inf],
180
200
```
181
201
182
202
请注意,保持不动(在主对角线上)的成本设置为:
203
+
183
204
* 对于非目的地节点,设为 ` np.inf ` --- 必须继续移动。
184
205
* 对于目的地节点,设为 0 --- 这是我们停止的地方。
206
+
185
207
对于到达成本函数的近似序列 $\{ J_n\} $,我们可以使用 NumPy 数组。
186
208
让我们尝试这个例子,看看效果如何:
187
209
188
210
``` {code-cell} python3
189
- nodes = range(7) # 节点 = 0, 1, ..., 6
211
+ nodes = range(7) # 节点 = 0, 1, ..., 6
190
212
J = np.zeros_like(nodes, dtype=int) # 初始猜测
191
213
next_J = np.empty_like(nodes, dtype=int) # 储存更新的猜测
192
214
@@ -201,14 +223,16 @@ while i < max_iter:
201
223
if np.array_equal(next_J, J):
202
224
break
203
225
204
- J[:] = next_J # 将 next_J 的内容复制到 J
226
+ J[:] = next_J # 将 next_J 的内容复制到 J
205
227
i += 1
206
228
207
229
print("到达成本函数是", J)
208
230
```
209
231
210
232
这与我们上面通过观察得到的数字相符。
233
+
211
234
但更重要的是,我们现在有了一种处理大型图的方法。
235
+
212
236
## 练习
213
237
214
238
``` {exercise-start}
@@ -218,10 +242,12 @@ print("到达成本函数是", J)
218
242
以下文本描述了一个加权有向图。
219
243
220
244
行 ` node0, node1 0.04, node8 11.11, node14 72.21 ` 表示从node0我们可以到达:
221
- * node1,代价为0.04
222
- * node8,代价为11.11
223
- * node14,代价为72.21
245
+ * node1,成本为0.04
246
+ * node8,成本为11.11
247
+ * node14,成本为72.21
248
+
224
249
从node0无法直接到达其他节点。
250
+
225
251
其他行具有类似的解释。
226
252
你的任务是使用上面给出的算法来找到最优路径及其代价。
227
253
@@ -367,10 +393,13 @@ def map_graph_to_distance_matrix(in_file):
367
393
return Q
368
394
```
369
395
396
+
370
397
此外,让我们编写
371
398
1 . 一个"贝尔曼算子"函数,该函数接受距离矩阵和当前的J估计值,并返回更新后的J估计值,以及
372
399
2 . 一个函数,该函数接受距离矩阵并返回一个代价函数。
400
+
373
401
我们将使用上述算法。
402
+
374
403
最小化步骤被向量化以提高速度。
375
404
376
405
``` {code-cell} python3
0 commit comments