搜索問題
graph TB
subgraph 盲目搜索
深度優先
寬度優先
end
subgraph 啟發式搜索
A算法
A*算法
end
盲目搜索
深度優先算法
沿著一個路徑按照一定規則順序搜索,直到搜到目標,或者搜到非法值。搜到非法值時,則返回到上一個點。
非法值有兩種形式,一種是問題本身定義的非法點(deadend),比如下棋的非法落子點;一種是當前點已經被充分展開,其展開點都被搜索過,最終都是非法點。
深度優先算法有兩個問題,對應的解決方法為:
- 深度問題
- 可以對搜索深度加以限制
- 死循環問題
- 記錄從初始狀態到當前狀態的搜索路徑
深度優先搜索的性質:
- 一般不能保證找到最優解
- 當深度限制不合理的時候可能找不到解
- 最壞的情況是窮舉
- 是一個通用方法,與問題無關
- 節省內存。只儲存從初始節點到當前節點的路徑。主要是因為按順序搜索
My Remark:
- 深度優先是一個很好的框架,在這個框架上可以衍生出很多算法。課上給出的LISP寫的框架要理解,每一步的作用,為什么這樣做。
- 深度優先的典型例子:四王后問題 4Queen
寬度優先算法
優先擴展深度淺的結點
學寬度優先的時候第一次引入了OPEN表和CLOSE表(大概?)那節課沒去聽不知道怎么講的。
每一層每一層展開,對于每一層,遍歷OPEN表,展開之后把父結點放進CLOSE表中。
寬度優先算法的性質:
- 當問題有解時,一定能找到解
- 當問題為單位耗散值,且有解時,一定能找到最優解
- 與寬度優先一樣,有通用性
- 效率比較低
- 儲存量大
My Remark
感覺寬度優先不是很有用,特別是問題比較復雜(可能的情況很多)的時候。
迭代加深搜索
寬度優先和深度優先都有明顯的缺點,所以就有了這個迭代加深搜索,來解決上述兩個方法不能找到最優解的問題。主要思想是給深度優先方法一個比較小的深度限制,然后逐漸增加深度限制,直到找到解,或者遍歷全局(反正最后都是有可能遍歷全局還找不到解的啊www)。
迭代加深搜索的計算時間分析
對于一個滿b叉樹,設最佳深度為d,則:
- 寬度優先產生的節點數:
N_{SF}=\sum_{i=0}y9zwglzb{i}=\dfrac{b^{d+1}-1}{b-1} - 迭代加深搜索產生的節點數:
N_{IDBT}=\sum_{i=0}b(d-i+1)bi=\dfrac{b}{b-1}N_{BF}-\dfrac{d+1}{b-1} - b>2\Rightarrow N_{IDBT}<\dfrac{b}{b-1}N_{BF}
啟發式搜索
相比盲目搜索的。盲目搜索相當于,要么優先深度,要么優先寬度,按照指定的方法來搜,跟問題沒有關系。事實上我們總是能對問題做出一些基礎分析,來降低搜索的工作量。這些基礎分析,構成啟發信息,就是啟發式搜索了。所以啟發式搜索方法的一個顯著優點是可以降低工作量。但是因為有一些引導信息,所以可能找到的解不是最優解。而且由于需要計算啟發信息,在最差的情況下,退化成盲目搜索,而且比盲目搜索工作量大(但是很少這么倒霉的啦)。
A算法
定義評價函數:
f(n)=g(n)+h(n)
其中,f(n)為評價函數,h(n)為啟發函數
通俗地解釋,對于結點n,g是從起點到n的最短路徑(嚴格地說,最短路徑的耗散值),h是n到目標點的最短路徑的耗散值。定義f為g和h的和,顯然這個f是可以評價n這個結點的好壞的。
My Remarks
- A算法的一個例子是8數碼問題。從這個例子可以感受到啟發式算法還是很神奇的。
A*算法
在A算法中,如果滿足條件:
$h(n)\leq h^*(n)$
那么稱A算法為A*算法。
- A*算法的兩個主要結論:
- 如果從初始結點到終點,存在路徑,那么A*一定能找打最優解(可采納性定理)
- 如果$h2(n)>h1(n)$,那么有$A1$的擴展結點數$\geq A2$的擴展結點數。
- 注意這里,擴展結點數指的是被擴展的結點的個數,也就是說每個結點最多只能被記數一次。
- h函數的生成方法:其中一個方法是,放寬原問題的條件,使原問題變為一個易于求解h的問題,用這個新問題的h*來代替h。
Vital Remarks
- A算法的停止條件,是到達目標點(h(n)=0),且目標點的f值在OPEN表中最小。這一點需要特別注意,因為有的時候,雖然達到了目標點,但是并不是最優路徑,或者并不是最優目標點。
- 在一些例子中,會發現,有些節點會被多次拓展。這是因為,這個被多次拓展的結點,在第一次被拓展的時候,并不是按照最優路徑拓展的。為了避免這種多次拓展,可以采取以下兩種方法:
- 對h加以限制。如果h是單調的,那么就可以避免多次拓展。
- h單調的定義:如果一個父結點到子節點的耗散值,大于子節點的h和父結點h之差,或者h=0,那么h是單調的。(h單調的本質是,任何一個路徑,f的變化趨勢與g是一致的,不回因為h的變化,使得f和g的變化趨勢不同。)
- h單調是A*算法的必要條件。(由h單調的定義,用反證法可以輕易證明。)
- 對算法進行修正。修正過程A:令$f_m$是目前已經擴展的結點中,最大的f。在進行下一步拓展時,選取f值比$f_m$小的結點,形成NEST表。選取NEST表中g值最小的點進行拓展。
- 由于h=0時,h是單調的,所以修正過程A中的h也是單調的,也就避免了重復擴展的問題。
- 對h加以限制。如果h是單調的,那么就可以避免多次拓展。