searching (informed and non-informed)

搜索基礎:
搜索算法需要構造搜索樹,樹中的每個節點應該包括以下元素:
1. 對應狀態空間中的狀態
2. 父節點
3. 父節點產生該節點時產生的行動

4. 代價,初始狀態到該節點的路徑消耗

樹搜索和圖搜索,樹搜索會存在環路的問題,因爲搜索A->B,後又搜索了B->A。圖搜索添加了一個搜索屬性搜索集,所有被搜索過的節點不會再被搜索,解決了環路問題。深度優先用樹搜索會出問題,解決方法是用深度限制搜索,以下會詳述。

無信息搜索策略:
1. 寬度優先搜索:用先進先出的隊列模擬搜索樹,迭代搜索,寬度優先搜索出來的一定是最優解,因爲不可能存在更短的路徑已經全都搜索過了。
時間複雜度: O(b^d)
空間複雜度:O(b^d)

b爲分叉,d爲最優解深度,由上面可知時間和空間複雜度都是很高

//queue中原來只有根節點
//搜索集原來爲空
BFS(){
			while(queue != NULL){
				node = pop(queue);
				把node添加進入搜索集中
				if (node不是所求解){
					for(node的所有子節點){
						if(該節點不在搜索集中)	insert(queue);
					}
				}
			}
		}



2. 一致代價搜索:用優先級隊列模擬搜索樹,當考慮擴展子節點的代價問題時,採用此法而不用寬搜可以保證最優解,每次擴展路徑代價最小的節點,例如從根節點到A,B,C的代價分別爲3,5,7,則首先擴展A,產生D,E,從根節點經A到D,E分別爲1,2,在B,C,D,E,中首先擴展D。以此類推。實際操作時,每個入隊的節點的優先級是根節點到達它的代價。寬度優先搜索是一直代價搜索在代價都相同的情況下的一個特例。
時間和空間複雜度類似於寬搜,但是不能用b和d表示。

3. 深度優先搜索:用後進先出的隊列模擬搜索樹,遞歸搜索。最明顯的缺點是搜出來的一般不是最優解,即,存在比第一個搜出來的解代價更小的解。
時間複雜度: O(b^m),稍遜於BFS,因爲這個複雜度一定會大於BFS的複雜度,但是具體大多少取決於m有多大,d有多小。
空間複雜度: O(bm)其中m是搜索樹的最深深度,一般來說這個值都會比O(b^d)小很多,除非m很大d很小。
//queue中原來只有根節點
//搜索集原來爲空

		DFS(){
			node = pop(queue);
				  把node添加進入搜索集中
			if(node 不是所求解){
				for (node的所有子節點){
					if(該節點不在搜索集中) {
						insert(queue);//擴展子節點添加進隊列
						DFS();//繼續搜子節點
					}
				}
			}
			else{
				打印
			}
		}




4. 深度受限搜索:給深度優先搜索樹設置一個深度,可以排除深度無限的樹無法搜索的情況,例如,羅馬尼亞的20個城市問題。如果深搜的不好可能會進入死循環(A->B, B->A, A->B。。。)
如果設置一個限制深度,例如19,則可以排除這個問題。


5. 迭代加深搜索:基於深度受限搜索,每次搜索深度增加1,能搜到最優解。且複雜度結合了深搜和寬搜的優點,是很好的搜索方法
時間複雜度: O(b^d)
空間複雜度: O(bd)

6.雙向搜索
雙向搜索比單向搜索優的直接原因是O(b^d)要大於2*O(b^(d/2))。
但是,某些問題無法使用雙向搜索。例如,目標狀態不明確的問題(八皇后)。而有些問題用雙向搜索則會快很多,例如八數碼問題和羅馬尼亞問題。
雙向搜索的目標檢測是判斷兩個方向的搜索的邊緣節點集是否有交集,若有的話則找到了一個解。缺點是即便兩邊都用寬搜也不能保證找到的解是最優解。
時間複雜度:O(b^(d/2))

空間複雜度: O(b^(d/2))


有信息(啓發式)搜索策略
1. 貪婪最佳優先搜索
啓發式的搜索策略是一種基於啓發函數的深度優先搜索,啓發函數h(n)是對節點n到目標狀態的代價評估函數。
舉例來說,在求最短路的問題中,A地到目的地的直線距離就可以作爲h(A)的值。貪婪最佳優先搜索算法在擴展節點時採用的策略是先擴展代價低的子節點,例如根節點有A,B,C三個子節點,其中A到目的地的代價最小,那麼我們首先擴展A。再從A開始根據A的子節點的啓發函數的值繼續擴展。
該算法存在兩個致命的問題
1. 搜索的結果不一定是最優的
每一步都貪心不能保證整體的最優
2. 樹搜索不完備(圖搜索是完備的)
如果採用樹搜索可能存在一種情況:A地的子節點中B的啓發函數值最小,B地的子節點中A的啓發函數值最小,這樣就會陷入A,B之間不停往返的死循環。

2. A*搜索
算法步驟:
定義:
開放列表
封閉列表
g(n):到達n節點所花費的代價
h(n):節點n到目的地的估計代價
f(n):經過n節點的最小代價解的估計代價
1. 將開始節點放入開放列表(開始節點的g值視爲0); 
2. 重複一下步驟:  
i. 在開放列表中查找具有最小f值的節點,並把查找到的節點作爲當前節點; 
ii. 把當前節點從開放列表刪除, 加入到封閉列表; 
iii. 對當前節點相鄰的每一個節點依次執行以下步驟:  
1. 如果該相鄰節點不可通行或者該相鄰節點已經在封閉列表中,則什麼操作也不執行,繼續檢驗下一個節點;  
2. 如果該相鄰節點不在開放列表中,則將該節點添加到開放列表中, 並將該相鄰節點的父節點設爲當前節點,同時計算並保存該相鄰節點的g,h,和f值;  
3. 如果該相鄰節點在開放列表中, 則判斷經由當前節點到達該相鄰節點的g值是否小於原來保存的g值,若小於,則將該相鄰節點的父節點設爲當前節點,並重新設置該相鄰節點的g和f值. 
iv. 循環結束條件: 當終點節點被加入到開放列表作爲待檢驗節點時, 表示路徑被找到,此時應終止循環;  或者當開放列表爲空,表明已無可以添加的新節點,而已檢驗的節點中沒有終點節點則意味着路徑無法被找到,此時也結束循環;  
3. 從終點節點開始沿父節點遍歷, 並保存整個遍歷到的節點座標,遍歷所得的節點就是最後得到的路徑;

保證最優性的條件
1. 可採納性
h(n)不會過高的估計從節點n到目的地的代價,即h(n)<=h^*(n)其中h^*(n)爲從節點n到目的地的實際代價
2. 一致性
從節點n到目的地的估計代價必須小於從節點n到節點n'的代價加上從n'到目的地的估計代價,即h(n)<=h(n')+cost(n,n'),這實際上是保證了三角不等式
一致都是可採納的,但是可採納不一定是一致的,要找出這個例子有難度,所以我們這裏先假設我們討論的h(n)都是一致的。

A*算法的最優性證明
可以證明,如果h(n)是可採納的,那麼它的樹搜索版本是最優的,如果h(n)是一致的,那麼它的圖搜索版本是最優的
我們先證明,如果h(n)是一致的,則沿着任何路徑的f(n)都是非遞減的。
假設在一條路徑上,n'是n的後繼,我們有
g(n') = cost(n,n') + g(n)
f(n') = g(n')+h(n') = g(n) + cost(n,n') + h(n') >= g(n) + h(n) = f(n)
既然f(n)是非遞減的,按照A*算法,我們每次選擇開啓列表中的f(n)最小的點,這樣可以保證n點第一次被選擇時的f(n)一定小於它以後被選擇時的f(n),原因很簡單,當你第一次選擇n點時開啓列表中其它所有點的f值都大於f(n),假如存在一條更短的路到達n點,那麼它必然經過開啓列表中的其它點,但是由於f函數是遞增的,其它點目前的f值已經大於f(n)了,經由它們的路徑長度肯定比f(n)更大。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章