Skip to content

Commit a670e20

Browse files
committed
Proofread BFS (CN)
1 parent c96840a commit a670e20

File tree

1 file changed

+15
-17
lines changed

1 file changed

+15
-17
lines changed

search/search-zh-cn.tex

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1522,7 +1522,7 @@ \subsubsection{跳棋趣题}
15221522
\label{fig:pegrules}
15231523
\end{figure}
15241524
1525-
这是跳棋的一种特殊形式。并不一定限制为6颗棋子,也可以是8或者更大的偶数。\cref{fig:pegpuzzles}是这类问题的变化形式\footnote{图片来源:\url{http://www.robspuzzlepage.com/jumping.htm}}。
1525+
这是跳棋的一种特殊形式。并不一定限制为6颗棋子,也可以是8或者更大的偶数。\cref{fig:pegpuzzles}是这类问题的变化形式\footnote{图片来源:\url{http://www.robspuzzlepage.com/jumping.htm}}。从左向右的石头位置为1, 2, ..., 7。每次有4种移动可能。例如开始时,第3块石头上的青蛙可以移动到空石头上。对称地,第5块石头上的青蛙也可以左移一步。第2块石头上的青蛙可以向右越过一只青蛙跳到空石头上,对称地,第6块石头上的青蛙,也可以向左越过一只。每次记录下7块石头和青蛙的状态,尝试4种方案。如果走不下去了,就回溯尝试其它方案。由于左侧的青蛙只能向右,右侧的只能向左,所有移动都是不可逆的。和走迷宫不同,这里不存在重复情况。我们记录移动的步骤用于最后输出结果。状态$L$是$s$的某种排列。$L[i]$的值是$0, \pm 1$表示第$i$个石头是空的、有一只向左、向右的青蛙。令空石头的位置为$p$,4种移动方案为:
15261526
15271527
\begin{figure}[htbp]
15281528
\centering
@@ -1533,16 +1533,14 @@ \subsubsection{跳棋趣题}
15331533
\label{fig:pegpuzzles}
15341534
\end{figure}
15351535
1536-
从左向右的石头位置为1, 2, ..., 7。每次有4种移动可能。例如开始时,第3块石头上的青蛙可以移动到空石头上。对称地,第5块石头上的青蛙也可以左移一步。第2块石头上的青蛙可以向右越过一只青蛙跳到空石头上,对称地,第6块石头上的青蛙,也可以向左越过一只。每次记录下7块石头和青蛙的状态,尝试4种方案。如果走不下去了,就回溯尝试其它方案。由于左侧的青蛙只能向右,右侧的只能向左,所有移动都是不可逆的。和走迷宫不同,这里不存在重复情况。我们记录移动的步骤用于最后输出结果。状态$L$$s$的某种排列。$L[i]$的值是$\pm 1, 0$表示第$i$个石头是空的、有一只向左、向右的青蛙。令空石头的位置为$p$4种移动方案为:
1537-
15381536
\begin{enumerate}
15391537
\item 向左跳跃:$p < 6$,且$L[p+2] > 0$,交换$L[p] \leftrightarrow L[p+2]$
15401538
\item 向左移动:$p < 7$,且$L[p+1] > 0$,交换$L[p] \leftrightarrow L[p+1]$
15411539
\item 向右跳跃:$p > 2$,且$L[p-2] < 0$,交换$L[p-2] \leftrightarrow L[p]$
15421540
\item 向右移动:$p > 1$,且$L[p-1] < 0$,交换$L[p-1] \leftrightarrow L[p]$
15431541
\end{enumerate}
15441542
1545-
定义4个函数$leap_l$$hop_l$$leap_r$$hop_r$,变化状态$L \mapsto L'$。若不能移动,则返回同样的$L$不变。使用栈$S$记录已做过的尝试。开始的时候,栈中只有一个列表,列表中只有开始状态。列表$M$记录所有找到的解。我们不断取出栈顶。如果状态$L = e$则找到了一个解。我们将移动步骤记录到$M$中。否则我们在$L$上尝试4种移动,如果可行就入栈以备继续搜索。
1543+
定义4个函数$leap_l$$hop_l$$leap_r$$hop_r$,变化状态$L \mapsto L'$。若不能移动,则返回同样的$L$不变。使用栈$S$记录已做过的尝试。开始的时候,栈中只有一个列表,列表中只有开始状态。列表$M$记录所有找到的解。我们不断取出栈顶。如果状态$L = e$则找到了一个解。我们将移动步骤记录到$M$中。否则我们在$L$上尝试4种移动,如果可行就入栈以备继续搜索。
15461544
15471545
\be
15481546
solve\ [[-1, -1, -1, 0, 1, 1, 1]]\ [\ ]
@@ -1610,7 +1608,7 @@ \subsubsection{跳棋趣题}
16101608
\hline
16111609
\etab
16121610
1613-
每侧有3只青蛙时需要15步左右互换。扩展上述解法可以得到步数和青蛙数目的一个关系表
1611+
每侧有3只青蛙时需要15步左右互换。扩展上述解法可以得到步数和青蛙数目的一个关系
16141612
16151613
\btab{c|c|c|c|c|c|c}
16161614
每侧青蛙数$n$ & 1 & 2 & 3 & 4 & 5 & ... \\
@@ -1625,7 +1623,7 @@ \subsubsection{跳棋趣题}
16251623
16261624
观察上面3个趣题,它们的解法有着类似的结构。它们都从某种状态开始。走迷宫从入口开始,八皇后问题从空棋盘开始,跳跃青蛙问题从[-1, -1, -1, 0, 1, 1, 1]开始。解的过程是一种搜索。每次尝试都有若干种可能的选项。走迷宫时,每步有上下左右四个方向选择;八皇后问题中,每次摆放都有八列选择;跳跃青蛙趣题中,每次有4种不同的跳跃方式选择。虽然每次选择都不知道能继续走多远。但我们始终清楚地知道最终状态是什么。走迷宫的最终状态是出口;八皇后问题的最终状态是八个皇后都摆在棋盘上;跳跃青蛙趣题的最终状态是左右青蛙位置互换。
16271625
1628-
我们使用相同的策略来解决这些问题:不断尝试可能的选项,记录已经达到的状态,如果无法继续就回溯并尝试其它选项。通过这样的方法,我们或者找到解,或者穷尽所有可能而发现问题无解。当然,这类解法存在一些变化,当找到一个解后,我们可以停下结束或者继续寻找所有可能的解。如果以起始状态为根,画出一棵树,每个树枝代表不同的选择。搜索过程是一个不断深入的过程。只要能继续,我们先不考虑同一深度上的其它选项。直到失败后回溯到树的上一层。如\cref{fig:dfs-tree}中的搜索顺序。箭头描述了如何先向下,在向上回溯的过程。节点上的数字是访问顺序。
1626+
我们使用相同的策略来解决这些问题:不断尝试可能的选项,记录已经达到的状态,如果无法继续就回溯并尝试其它选项。通过这样的方法,我们或者找到解,或者穷尽所有可能而发现问题无解。当然,这类解法存在一些变化,当找到一个解后,我们可以停下结束或者继续寻找所有可能的解。如果以起始状态为根,画出一棵树,每个树枝代表不同的选择。搜索过程是一个不断深入的过程。只要能继续,我们先不考虑同一深度上的其它选项。直到失败后回溯到树的上一层。如\cref{fig:dfs-tree}中的搜索顺序。箭头描述了如何先向下,再向上回溯的过程。节点上的数字是访问顺序。
16291627
16301628
\begin{figure}[htbp]
16311629
\centering
@@ -1646,7 +1644,7 @@ \subsubsection{跳棋趣题}
16461644
c(h, f).
16471645
\end{lstlisting}
16481646
1649-
其中,断言$c(X, Y)$表示位置$X$$Y$连通。这一断言是有方向性的。如果要让$Y$$X$连通,我们可以增加一条对称的断言,或者建立一条无方向性的断言。\cref{fig:directed-graph}给出了一个有向图。任给位置$X$$Y$,Prolog可以通过下面的程序判定它们之间是否有通路。
1647+
其中断言$c(X, Y)$表示位置$X$$Y$连通。断言是有方向性的。如果要让$Y$$X$连通,我们可以增加一条对称的断言,或者建立一条无方向性的断言。\cref{fig:directed-graph}给出了一个有向图。任给位置$X$$Y$,Prolog可以通过下面的程序判定它们之间是否有通路。
16501648
16511649
\begin{figure}[htbp]
16521650
\centering
@@ -1697,16 +1695,16 @@ \subsubsection{狼、羊、白菜过河问题}
16971695
16981696
由于狼不会吃掉白菜,农夫可以安全地将羊运到河对岸并返回。接下来无论将狼或白菜中的任何一样运过河,他必须将某一样运回以避免有东西被吃掉。为了寻找最快的渡河方法,我们并发检查所有的选项,比较哪个更快。不考虑渡河的方向,每渡过一次算做一步,往返算两步。我们检查渡河一次后的所有可能、两次后所有可能、三次后的所有可能……直到某次后,所有的东西都到达了对岸结束。并且这一渡河方法在所有可能中胜出,是最快的解法。
16991697
1700-
如何“并发”检查所有可能的解法?考虑一个抽奖游戏。参与者闭着眼睛从箱子里摸出一个球。箱子里只有一个黑球,其余的球都是白色的。摸到黑球获胜,摸到白球则放回箱子,然后等待下次摸球。为了使游戏公平,可以制定这样一个规则:必须等所有人都摸过之后才能再摸第二次。参与游戏的人站成一队。每次站在队伍前面的人摸球,如果他没有摸到黑球获胜,就站到队尾等待下次摸球。这一队列可以保证游戏的公平。
1698+
如何“并发”检查所有可能的解法?考虑一个抽奖游戏。参与者闭着眼睛从箱子里摸出一个球。箱子里只有一个黑球,其余的球都是白色的。摸到黑球获胜,摸到白球则放回箱子,然后等待下次摸球。为了使游戏公平,可以制定这样一个规则:必须等所有人都摸过之后才能再摸第二次。参与游戏的人站成一队。每次站在队伍前面的人摸球,如果他没有摸到黑球,就站到队尾等待下次摸球。这一队列可以保证游戏的公平。
17011699
17021700
\begin{figure}[htbp]
17031701
\centering
17041702
\includegraphics[scale=0.5]{img/luckydraw-queue}
1705-
\caption{第$i$个人出队摸球。如果没有摸到黑球就站到队尾}
1703+
\caption{第$i$个人出队摸球。如果没有摸到黑球就站到队尾}
17061704
\label{fig:luck-draw}
17071705
\end{figure}
17081706
1709-
用类似的思路来解决渡河问题。用集合$A$$B$代表河两岸。开始时,集合$A = \{w, g, c, p\}$包含狼、羊、白菜、农夫,集合$B = \nil$。每次将农夫和另外一个元素在集合间移动。如果集合中不存在农夫,则不能含相互冲突的东西。目标是用最少的次数交换$A$$B$的内容。使用一个队列$Q$包含起始状态$A = \{w, g, c, p\}$$B=\nil$。只要队列不空,我们就取出头部元素,扩展所有可能的选择。然后将扩展后的状态放回队尾。如果队列头部等于$A=\nil$$B=\{w, g, c, p\}$,我们就找到了解。\cref{fig:bfs-tree}描述了搜索顺序。同一深度上的所有可能都被检查了,无需进行回溯。
1707+
用类似的思路来解决渡河问题。用集合$A$$B$代表河两岸。开始时,集合$A = \{w, g, c, p\}$包含狼、羊、白菜、农夫,集合$B = \nil$。每次将农夫和另外一个元素在集合间移动。如果集合中不存在农夫,则不能含有相互冲突的东西。目标是用最少的次数交换$A$$B$的内容。使用一个队列$Q$包含起始状态$A = \{w, g, c, p\}$$B=\nil$。只要队列不空,我们就取出头部元素,扩展所有可能的选择。然后将扩展后的状态放回队尾。如果队列头部等于$A=\nil$$B=\{w, g, c, p\}$,我们就找到了解。\cref{fig:bfs-tree}描述了搜索顺序。同一深度上的所有可能都被检查了,无需进行回溯。
17101708
17111709
\begin{figure}[htbp]
17121710
\centering
@@ -1820,7 +1818,7 @@ \subsubsection{倒水问题}
18201818
\label{fig:jugs-r2}
18211819
\end{figure}
18221820
1823-
大小两个瓶子$B, A$,每次有6种操作:(1) 小瓶子$A$装满水;(2) $B$装满水;(3) 倒空$A$;(4) 倒空$B$;(5) 将$A$中的水倒入$B$;(6) 将$B$倒入$A$。下表是一系列倒水动作,假设容积$a < b < 2a$
1821+
大小两个瓶子$B, A$,每次有6种操作:(1) $A$装满水;(2) $B$装满水;(3) 倒空$A$;(4) 倒空$B$;(5) 将$A$中的水倒入$B$;(6) 将$B$倒入$A$。下表是一系列倒水动作,假设容积$a < b < 2a$
18241822
18251823
\btab{l|l|l}
18261824
$A$ & $B$ & 操作 \\
@@ -1910,17 +1908,17 @@ \subsubsection{倒水问题}
19101908
丢番图方程$g = x a + b y$有无穷多个解,$|x| + |y|$越小,所需步骤越少。我们可以采用类似“过河问题”的思路。在6种操作中(倒满$A$、倒满$B$、将$A$倒入$B$……)“并行”尝试出最优解。使用一个队列来安排所有的尝试。队列中的元素是一系列值对$(p, q)$$p$$q$分别是两瓶中水的体积,记录了从开始到最后的倒水操作。开始时队列内容为:$\{[(0, 0)]\}$
19111909
19121910
\be
1913-
solve\ a\ b\ g = bfs \{ [(0, 0)] \}
1911+
solve\ a\ b\ g = \textit{bfs} \{ [(0, 0)] \}
19141912
\ee
19151913
19161914
只要队列不空,我们从头部取出一操作序列。如果序列中的最后状态包含$g$升水,我们就找到了一个解。我们将序列逆序输出;否则我们扩展最后的状态,尝试6种可能,去掉重复的并入队。
19171915
19181916
\be
19191917
\begin{array}{rcl}
1920-
bfs\ \nil & = & [\ ] \\
1921-
bfs\ Q & = & \begin{cases}
1918+
\textit{bfs}\ \nil & = & [\ ] \\
1919+
\textit{bfs}\ Q & = & \begin{cases}
19221920
p \text{或} q = g: & \textit{reverse}\ s, \text{其中} (p, q) = head\ s, (s, Q') = pop\ Q \\
1923-
\text{否则}: & bfs\ (pushAll\ (map\ (:s)\ (try\ s))\ Q')
1921+
\text{否则}: & \textit{bfs}\ (pushAll\ (map\ (:s)\ (try\ s))\ Q')
19241922
\end{cases}
19251923
\end{array}
19261924
\ee
@@ -2061,7 +2059,7 @@ \subsubsection{华容道}
20612059
\label{fig:klotski-jp}
20622060
\end{figure}
20632061
2064-
我们用$5 \times 4$矩阵来代表棋盘,行列从0开始。110个数字代表棋子。0代表空位置。矩阵$M$给出了华容道的初始状态。值为$i$的格子表示有棋子占据。布局用字典$L$代表。$L[i]$棋子$i$覆盖的位置集合。例如$L[4] = \{(2, 1), (2, 2)\}$表示第4个棋子覆盖了位置$(2, 1)$$(2, 2)$。我们可以把棋盘上的20个位置编号为019,把行列转化为编号:$c = 4y + x$。这样第四个棋子占据$L[4] = \{9, 10\}$
2062+
我们用$5 \times 4$矩阵来代表棋盘,行列从0开始。110个数字代表棋子。0代表空位置。矩阵$M$给出了华容道的初始状态。值为$i$的格子表示有棋子占据。布局用字典$L$代表。$L[i]$是棋子$i$覆盖的位置集合。例如$L[4] = \{(2, 1), (2, 2)\}$表示第4个棋子覆盖了位置$(2, 1)$$(2, 2)$。我们可以把棋盘上的20个位置编号为019,把行列转化为编号:$c = 4y + x$。这样第四个棋子占据$L[4] = \{9, 10\}$
20652063
20662064
\[
20672065
\begin{array}{cc}
@@ -2259,7 +2257,7 @@ \subsubsection{华容道}
22592257
\label{fig:dfs-bfs-tree}
22602258
\end{figure}
22612259
2262-
由于我们无法真正的“并行”搜索,广度优先搜索使用队列来记录尝试。从队列头部不断取出步骤较少的候选项,从队列尾部不断加入步骤较多的新候选项。广度优先搜索提供了一种简单的方法寻找最少步骤解,但它不能直接搜索其它最优解。考虑如\cref{fig:weighted-dag}的有向图,每段路径长度不同,我们无法用广度优先搜索找出两个城市之间的最短路径。注意从城市$a$到城市$c$之间的最短路径并非经过最少城市的$a \to b \to c$。这条路径的总长度为22;而是经过更多城市的路径$a \to e \to f \to c$他的总长度只有20
2260+
由于我们无法真正的“并行”搜索,广度优先搜索使用队列来记录尝试。从队列头部不断取出步骤较少的候选项,从队列尾部不断加入步骤较多的新候选项。广度优先搜索提供了一种简单的方法寻找最少步骤解,但它不能直接搜索其它最优解。考虑如\cref{fig:weighted-dag}的有向图,每段路径长度不同,我们无法用广度优先搜索找出两个城市之间的最短路径。注意从城市$a$到城市$c$之间的最短路径并非经过最少城市的$a \to b \to c$。这条路径的总长度为22;而是经过更多城市的路径$a \to e \to f \to c$它的总长度只有20
22632261
22642262
\begin{figure}[htbp]
22652263
\centering

0 commit comments

Comments
 (0)