1. 程式人生 > >搜尋_優先佇列BFS_A*_演算法分析

搜尋_優先佇列BFS_A*_演算法分析

1, 優先佇列BFS

    下面是優先佇列BFS虛擬碼:

//在解空間G上以s為源結點執行優先佇列BFS
Priority_BFS(G, s) 
	建立初始僅包含結點s且以s的權重(代價)s.w為關鍵字的最小堆Q
	while Q非空
		結點u = Q.top()
		Q.pop()
		for(解空間G中所有未入過佇列的u的鄰接結點v) 
			Q.push(v) 

    結論1: 在演算法Priority_BFS每次執行第5行時, 如果接下來的第7行if條件成立, 那麼Q的堆頂也即結點u對應狀態g的代價最小, 注意: 對於任意從源結點s出發, 且終點為e的路徑L, 如果e具有其對應狀態的最小代價, 那麼L上所有結點都具有其對應狀態的最小代價.

    證明: 設執行第5時接下來的第7行if條件成立, 滿足Q的堆頂結點u對應的狀態為a, 代價為w, 設解空間G中從源結點s達到狀態a的最小代價為w{}', 並取解空間中任意一個對應狀態a且代價為w{}'的結點為b. 且a到b的一條包含節點數最少的路徑為R = c_{1}c_{2}...c_{n}(c_{i - 1}c_{i}的前驅結點, c_{1}=s, c_{n}=b).

    設狀態a_{0}為所有滿足w > w{}'且R包含結點數最少的a型別狀態, 也即當a取a_{0}時路徑R中除終點a_{0}外的所有結點對應的狀態均滿足結論1,  那麼R中任意結點的代價(Q中對應關鍵字)均小於w, 根據結點u為狀態a第一次出佇列Q, 那麼必有在u出佇列之前, 結點b未入佇列Q, 對於R上b的前驅結點c_{n-1}

亦不能入佇列Q, 因為如果c_{n-1}之前入佇列Q, 那麼在u出佇列之前c_{n-1}已經出佇列, 在c_{n-1}出佇列對應的第8至9行的迴圈中將把結點b入佇列Q, 則結點b將在結點u之前出隊, 與u為所有對應狀態a_{0}的結點中第一個出隊矛盾, 因此c_{n-1}不應在u出佇列之前入隊, 使用數學歸納法易推出在路徑R上如果c_{j}(j >= 2)不能在u出隊之前入隊, 那麼c_{j - 1}亦不能再u出隊之前之前入隊, 也即R上所有結點均不能在u出隊之前入隊, 則R的起點s也不應在u出隊之前入隊, 這顯然是不可能的.因此不存在滿足w > w{}'的狀態, 結論1得證.

2, A*

    A*演算法為每個結點u對應的狀態a設立一個估價函式f, 滿足f(a)不大於從從狀態a轉移至目標狀態T的最小代價, 下面是A*演算法的虛擬碼:

//在解空間G上以s為源結點, T為目標狀態執行A*_BFS, 返回目標狀態T的最小代價 
A*_BFS(G, s, T) 
	建立初始僅包含結點s且以s的權重(代價)s.w與s的估價函式s.f之和為關鍵字的最小堆Q
	while Q非空
		結點u = Q.top()
		if u對應狀態為T
			return u.w 
		Q.pop()
		for(解空間G中所有滿足未入過佇列Q的u的鄰接結點v) 
				Q.push(v) 

    結論2: 演算法A*_BFS(G, s, T)返回解空間G中從源結點s到目標狀態T的最小代價, 注意: 解空間中所有以s為起點的路徑滿足路徑上所有b的前驅結點a使得a.w <= b.w(w對應結點的當前代價, 通常解空間樹中第i層結點的w屬性值為i)成立

     證明: 假設演算法A*_BFS(G, s, T)返回的並非解空間G中從源結點s到目標狀態T的最小代價, 設非解空間G中從源結點s到目標狀態T的最小代價為g, 設G中結點e滿足: e對應狀態為T且e.w = g, 則e.f = 0, 設R為從源結點s到e的一條路徑, 則R所有結點對應的當前代價和估價函式值之和均不超過e.w, 設最後一次執行第5行時對應Q的堆頂結點u為k, 顯然在k成為堆頂之前, 結點e不能入佇列Q, 否則在e成為堆頂之前k不能成為堆頂, 這與k為所有對應狀態T的結點中第一個成為堆頂矛盾, 類似於結論1的證明過程, 使用數學歸納法易推出, 在k成為堆頂之前R上的所有結點均不能入佇列Q, 則源結點s在k成為堆頂之前不能入佇列Q, 這顯然是不可能的, 因此假設不成立, 結論2得證.