本文轉自http://blog.csdn.net/u014800748/article/details/47376435
迭代加深搜索(IDDFS)的思想
迭代加深搜索一般用來求解狀態樹“非常深”,甚至深度可能趨於無窮,但是“目標狀態淺”的問題。如果用普通的DFS去求解,往往效率不夠高。此時我們可以對DFS進行一些改進。最直觀的一種辦法是增加一個搜索的最大深度限制maxd,一般是從1開始。每次搜索都要在maxd深度之內進行,如果沒有找到解,就繼續增大maxd,直到成功找到解,然後break。
如下圖所示,如果用DFS,需要15步才能找到結點3,但是用迭代加深搜索,很快即可找到結點3。
在使用迭代加深搜索時,通常還要引入一個估價函數h(),來預測從當前深度還有至少多少步才能到達目標狀態。假設當前在第cur層,當cur+h(cur)>maxd時候,就說明不論怎麼走,都不可能在maxd的限制之內找到目標狀態,此時就可以進行“剪枝”操作。這樣的和帶有估價函數的迭代加深搜索就是IDA*算法。爲了更好的理解該算法,下面以“埃及分數”這一經典的例子來作爲說明。
埃及分數問題
在古埃及,人們使用單位分數的和(即1/a,a是自然數)來表示一切有理數,例如,2/3=1/2+1/6,但是不允許2/3=1/3+1/3,因爲在加數中不允許有相同的。對於一個分數a/b,表示的方法有很多種,其中加數少的比加數多的好,如果加數個數相同,那麼最小的分數越大越好。例如,19/45=1/5+1/6+1/18是最優方案。
輸入兩個整數a,b(0<a<b<500),試編程計算最佳表達式。
樣例輸入:
495 499
樣例輸出:
Case 1: 495/499=1/2+1/5+1/6+1/8+1/3992+1/14970
問題分析
首先,根據題意可以發現,本題的解答樹非常的龐大,不僅深度沒有明顯的上界,而且在理論上加數的選擇也是無限的,即每一層的結點數量也是無限的。這樣的話,如果使用普通的BFS,第一層都擴展不完。然而本題要實現兩個目標:1.加數的個數儘量少。2.最小的那個分數儘量大,即最大的分母儘量小。
爲了實現第一個目標,我們自然想到可以逐一枚舉可能的個數,設maxd表示一共有maxd+1個分數相加恰好等於a/b(下標從0開始),按照這樣的思路,一定可以找到加數最少的解。
接下來考慮如何實現第二個目標。第二個目標其實是在告訴我們如果存在多解的時候,要更新當前找到的最優解。這裏容易犯的一個錯誤是:找到了解之後立即全部return true。這樣的寫法只能實現目標1,並沒有真正實現目標2。
那麼自然會問:那正確的做法是什麼?正確的做法應該是找到了一組解後,繼續返回上一層繼續新的搜索。假設當前已經在第cur層,即0~cur的所有的分母都已經確定了,剩下的分數還需要aa/bb,再假設我們此時需要從分母i>=from的數開始尋找,不難發現,如果(maxd+1-d)*(1/i)≤aa/bb,即剩下的分數全部都爲1/i時候,他們的和纔剛好等於aa/bb。而實際情況是:分母不允許重複出現,即實際的和肯定小於(maxd+1-d)*(1/i),這個時候如果i繼續增加,(maxd+1-d)*(1/i)只會更小於aa/bb,情況更糟糕,因此在此處應該停止枚舉。這樣,我們就分析出來了正確的停止搜索的條件:當出現(maxd+1-d)*(1/i)≤aa/bb時,break。
通過以上分析,我們還確定出來了dfs時候的入口參數: cur表示當前在第cur層,from表示第cur層分母的起點, aa表示剩下的分數的分子,bb表示剩下的分數的分母。即dfs(cur,from,aa,bb)。至此,本題的算法的整體框架已經分析完畢了,我們成功地利用IDA*算法解決了這道經典例題。
代碼: