方法
有兩種常用的方法可用來選擇下一個E-節點(雖然也可能存在其他的方法):1) 先進先出(F I F O) 即從活節點表中取出節點的順序與加入節點的順序相同,因此活節點表的性質與佇列相同。
2) 最小耗費或最大收益法在這種模式中,每個節點都有一個對應的耗費或收益。如果查找一個具有最小耗費的解,則活節點表可用最小堆來建立,下一個E-節點就是具有最小耗費的活節點;如果希望搜尋一個具有最大收益的解,則可用最大堆來構造活節點表,下一個E-節點是具有最大收益的活節點。
例子
例5-1 【迷宮老鼠】 考察圖16-3a 給出的迷宮老鼠例子和圖1 6 - 1的解空間結構。使用F I F O分枝定界,初始時取(1,1)作為E-節點且活動佇列為空。迷宮的位置( 1 , 1)被置為1,以免再次返回到這個位置。(1,1)被擴充,它的相鄰節點( 1,2)和(2,1)加入到佇列中(即活節點表)。為避免再次回到這兩個位置,將位置( 1,2)和(2,1)置為1。此時迷宮如圖1 7 - 1 a所示,E-節點(1,1)被刪除。節點(1,2)從佇列中移出並被擴充。檢查它的三個相鄰節點(見圖1 6 - 1的解空間),只有(1,3)是可行的移動(剩餘的兩個節點是障礙節點),將其加入佇列,並把相應的迷宮位置置為1,所得到的迷宮狀態如圖17-1b 所示。節點(1,2)被刪除,而下一個E-節點(2,1)將會被取出,當此節點被展開時,節點(3,1)被加入佇列中,節點(3,1)被置為1,節點(2,1)被刪除,所得到的迷宮如圖17-1c 所示。此時佇列中包含(1,3)和(3,1)兩個節點。隨後節點(1,3)變成下一個E-節點,由於此節點不能到達任何新的節點,所以此節點即被刪除,節點(3,1)成為新的E-節點,將佇列清空。節點( 3,1)展開,(3,2)被加入佇列中,而(3,1)被刪除。(3,2)變為新的E-節點,展開此節點後,到達節點(3,3),即迷宮的出口。
使用F I F O搜尋,總能找出從迷宮入口到出口的最短路徑。需要注意的是:利用回溯法找到的路徑卻不一定是最短路徑。有趣的是,程式6 - 11已經給出了利用F I F O分枝定界搜尋從迷宮的(1,1)位置到(n,n) 位置的最短路徑的代碼。
例5-2 【0/1背包問題】 下面比較分別利用F I F O分枝定界和最大收益分枝定界方法來解決如下背包問題:n=3, w=【20,15,15】, p=【40,25,25】, c= 3 0。F I F O分枝定界利用一個佇列來記錄活節點,節點將按照F I F O順序從佇列中取出;而最大收益分枝定界使用一個最大堆,其中的E-節點按照每個活節點收益值的降序,或是按照活節點任意子樹的葉節點所能獲得的收益估計值的降序從佇列中取出。本例所使用的背包問題與例1 6 . 2相同,並且有相同的解空間樹。
使用F I F O分枝定界法搜尋,初始時以根節點A作為E-節點,此時活節點佇列為空。當節點
A展開時,生成了節點B和C,由於這兩個節點都是可行的,因此都被加入活節點佇列中,節點A被刪除。下一個E-節點是B,展開它並產生了節點D和E,D是不可行的,被刪除,而E被加入佇列中。下一步節點C成為E-節點,它展開後生成節點F和G,兩者都是可行節點,加入佇列中。下一個E-節點E生成節點J和K,J不可行而被刪除,K是一個可行的葉節點,並產生一個到目前為止可行的解,它的收益值為4 0。
下一個E-節點是F,它產生兩個孩子L、M,L代表一個可行的解且其收益值為5 0,M代表另一個收益值為1 5的可行解。G是最後一個E-節點,它的孩子N和O都是可行的。由於活節點佇列變為空,因此搜尋過程終止,最佳解的收益值為5 0。
可以看到,工作在解空間樹上的F I F O分枝定界方法非常象從根節點出發的寬度優先搜尋。它們的主要區別是在F I F O分枝定界中不可行的節點不會被搜尋。最大收益分枝定界算法以解空間樹中的節點A作為初始節點。展開初始節點得到節點B和C,兩者都是可行的並被插入堆中,節點B獲得的收益值是4 0(設x1 = 1),而節點C得到的收益值為0。A被刪除,B成為下一個E-節點,因為它的收益值比C的大。當展開B時得到了節點D和E,D是不可行的而被刪除,E加入堆中。由於E具有收益值4 0,而C為0,因為E成為下一個E-節點。
展開E時生成節點J和K,J不可行而被刪除,K是一個可行的解,因此K為作為目前能找到的最優解而記錄下來,然後K被刪除。由於只剩下一個活節點C在堆中,因此C作為E-節點被展開,生成F、G兩個節點插入堆中。F的收益值為2 5,因此成為下一個E-節點,展開後得到節點L和M,但L、M都被刪除,因為它們是葉節點,同時L所對應的解被作為當前最優解記錄下來。最終,G成為E-節點,生成的節點為N和O,兩者都是葉節點而被刪除,兩者所對應的解都不比當前的最優解更好,因此最優解保持不變。此時堆變為空,沒有下一個E-節點產生,搜尋過程終止。終止於J的搜尋即為最優解。
猶如在回溯方法中一樣,可利用一個定界函式來加速最優解的搜尋過程。定界函式為最大收益設定了一個上限,通過展開一個特殊的節點可能獲得這個最大收益。如果一個節點的定界函式值不大於目前最優解的收益值,則此節點會被刪除而不作展開,更進一步,在最大收益分枝定界方法中,可以使節點按照它們收益的定界函式值的非升序從堆中取出,而不是按照節點的實際收益值來取出。這種策略從可能到達一個好的葉節點的活節點出發,而不是從目前具有較大收益值的節點出發。
例5-3 【旅行商問題】 對於圖1 6 - 4的四城市旅行商問題,其對應的解空間為圖1 6 - 5所示的排列樹。F I F O分枝定界使用節點B作為初始的E-節點,活節點佇列初始為空。當B展開時,生成節點C、D和E。由於從頂點1到頂點2,3,4都有邊相連,所以C、D、E三個節點都是可行的並加入佇列中。當前的E-節點B被刪除,新的E-節點是佇列中的第一個節點,即節點C。因為在圖1 6 - 4中存在從頂點2到頂點3和4的邊,因此展開C,生成節點F和G,兩者都被加入佇列。下一步,D成為E-節點,接著又是E,到目前為止活節點佇列中包含節點F到K。下一個E-節點是F,展開它得到了葉節點L。至此找到了一個旅行路徑,它的開銷是5 9。展開下一個E-節點G,得到葉節點M,它對應於一個開銷為6 6的旅行路徑。接著H成為E-節點,從而找到葉節點N,對應開銷為2 5的旅行路徑。下一個E-節點是I,它對應的部分旅行1 - 3 - 4的開銷已經為2 6,超過了目前最優的旅行路徑,因此, I不會被展開。最後,節點J,K成為E-節點並被展開。經過這些展開過程,佇列變為空,算法結束。找到的最優方案是節點N所對應的旅行路徑。
如果不使用F I F O方法,還可以使用最小耗費方法來搜尋解空間樹,即用一個最小堆來存儲活節點。這種方法同樣從節點B開始搜尋,並使用一個空的活節點列表。當節點B展開時,生成節點C、D和E並將它們加入最小堆中。在最小堆的節點中, E具有最小耗費(因為1 - 4的局部旅行的耗費是4),因此成為E-節點。展開E生成節點J和K並將它們加入最小堆,這兩個節點的耗費分別為1 4和2 4。此時,在所有最小堆的節點中,D具有最小耗費,因而成為E-節點,並生成節點H和I。至此,最小堆中包含節點C、H、I、J和K,H具有最小耗費,因此H成為下一個E-節點。展開節點E,得到一個完整的旅行路徑1 - 3 - 2 - 4 - 1,它的開銷是2 5。節點J是下一個E-節點,展開它得到節點P,它對應於一個耗費為2 5的旅行路徑。節點K和I是下兩個E-節點。由於I的開銷超過了當前最優的旅行路徑,因此搜尋結束,而剩下的所有活節點都不能使我們找到更優的解。
對於例5 - 2的背包問題,可以使用一個定界函式來減少生成和展開的節點數量。這種函式將確定旅行的最小耗費的下限,這個下限可通過展開某個特定的節點而得到。如果一個節點的定界函式值不能比當前的最優旅行更小,則它將被刪除而不被展開。另外,對於最小耗費分枝定界,節點按照它在最小堆中的非降序取出。
在以上幾個例子中,可以利用定界函式來降低所產生的樹型解空間的節點數目。當設計定界函式時,必須記住主要目的是利用最少的時間,在記憶體允許的範圍內去解決問題。而通過產生具有最少節點的樹來解決問題並不是根本的目標。因此,我們需要的是一個能夠有效地減少計算時間並因此而使產生的節點數目也減少的定界函式。
回溯法比分枝定界在占用記憶體方面具有優勢。回溯法占用的記憶體是O(解空間的最大路徑長度),而分枝定界所占用的記憶體為O(解空間大小)。對於一個子集空間,回溯法需要(n)的記憶體空間,而分枝定界則需要O ( 2n ) 的空間。對於排列空間,回溯需要(n) 的記憶體空間,分枝定界需要O (n!) 的空間。雖然最大收益(或最小耗費)分枝定界在直覺上要好於回溯法,並且在許多情況下可能會比回溯法檢查更少的節點,但在實際套用中,它可能會在回溯法超出允許的時間限制之前就超出了記憶體的限制。