動態規划--國王挖金礦問題


     子問題:

       國王需要根據兩個大臣的答案以及第9座金礦的信息才能判斷出最多能夠開采出多少金子。為了解決自己面臨的問題,他需要給別人制造另外兩個問題,這兩個問題就是子問題。

 

       思考動態規划的第一點----最優子結構:

       國王相信,只要他的兩個大臣能夠回答出正確的答案(對於考慮能夠開采出的金子數,最多的也就是最優的同時也就是正確的),再加上他的聰明的判斷就一定能得到最終的正確答案。我們把這種子問題最優時母問題通過優化選擇后一定最優的情況叫做“最優子結構”。

 

       思考動態規划的第二點----子問題重疊:

       實際上國王也好,大臣也好,所有人面對的都是同樣的問題,即給你一定數量的人,給你一定數量的金礦,讓你求出能夠開采出來的最多金子數。我們把這種母問題與子問題本質上是同一個問題的情況稱為“子問題重疊”。然而問題中出現的不同點往往就是被子問題之間傳遞的參數,比如這里的人數和金礦數。

      

       思考動態規划的第三點----邊界:

       想想如果不存在前面我們提到的那些底層勞動者的話這個問題能解決嗎?永遠都不可能!我們把這種子問題在一定時候就不再需要提出子子問題的情況叫做邊界,沒有邊界就會出現死循環。

 

       思考動態規划的第四點----子問題獨立:

       要知道,當國王的兩個大臣在思考他們自己的問題時他們是不會關心對方是如何計算怎樣開采金礦的,因為他們知道,國王只會選擇兩個人中的一個作為最后方案,另一個人的方案並不會得到實施,因此一個人的決定對另一個人的決定是沒有影響的。我們把這種一個母問題在對子問題選擇時,當前被選擇的子問題兩兩互不影響的情況叫做“子問題獨立”。

 

 

       這就是動態規划,具有“最優子結構”、“子問題重疊”、“邊界”和“子問題獨立”,當你發現你正在思考的問題具備這四個性質的話,那么恭喜你,你基本上已經找到了動態規划的方法。

        有了上面的這幾點,我們就可以寫出動態規划的轉移方程式,現在我們來寫出對應這個問題的方程式,如果用gold[mineNum]表示第mineNum個金礦能夠挖出的金子數,用peopleNeeded[mineNum]表示挖第mineNum個金礦需要的人數,用函數f(people,mineNum)表示當有people個人和編號為0、1、2、3、……、mineNum的金礦時能夠得到的最大金子數的話,f(people,mineNum)等於什么呢?或者說f(people,mineNum)的轉移方程是怎樣的呢?

 

       答案是:

       當mineNum = 0且people >= peopleNeeded[mineNum]時 f(people,mineNum) = gold[mineNum]

       當mineNum = 0且people < peopleNeeded[mineNum]時 f(people,mineNum) = 0

 

       當mineNum != 0時 f(people,mineNum) = f(people-peopleNeeded[mineNum], mineNum-1) + gold[mineNum]與f(people, mineNum-1)中的較大者,前兩個式子對應動態規划的“邊界”,后一個式子對應動態規划的“最優子結構”請讀者弄明白后再繼續往下看。

    思考動態規划的第五點----做備忘錄:

       正如上面所說的一樣,當我們遇到相同的問題時,我們可以問同一個人。講的通俗一點就是,我們可以把問題的解放在一個變量中,如果再次遇到這個問題就直接從變量中獲得答案,因此每一個問題僅會計算一遍,如果不做備忘的話,動態規划就沒有任何優勢可言了。             

 

       思考動態規划的第六點----時間分析:

       正如上面所說,如果我們用窮舉的方法,至少需要2^n個常數時間,因為總共有2^n種情況需要考慮,如果在背包問題中,包的容量為1000,物品數為100,那么需要考慮2^100種情況,這個數大約為10的30次方。

       而如果用動態規划,最多大概只有1000*100 = 100000個不同的問題,這和10的30次方比起來優勢是很明顯的。而實際情況並不會出現那么多不同的問題,比如在金礦模型中,如果所有的金礦所需人口都是1000個人,那么問題總數大約只有100個。

 

       非正式地,我們可以很容易得到動態規划所需時間,如果共有questionCount個相同的子問題,而每一個問題需要面對chooseCount種選擇時,我們所需時間就為questionCount * chooseCount個常數。在金礦模型中,子問題最多有大概people * n 個(其中people是用於開采金礦的總人數,n是金礦的總數),因此questionCount = people * n,而就像國王需要考慮是采用左部下的結果還是采用右部下的結果一樣,每個問題面對兩個選擇,因此chooseCount = 2,所以程序運行時間為 T = O(questionCount * chooseCount) =O(people * n),別忘了實際上需要的時間小於這個值,根據所遇到的具體情況有所不同。

 

 那么遇到問題如何用動態規划去解決呢?根據上面的分析我們可以按照下面的步驟去考慮:

       1、構造問題所對應的過程。

       2、思考過程的最后一個步驟,看看有哪些選擇情況。

       3、找到最后一步的子問題,確保符合“子問題重疊”,把子問題中不相同的地方設置為參數。

       4、使得子問題符合“最優子結構”。

       5、找到邊界,考慮邊界的各種處理方式。

       6、確保滿足“子問題獨立”,一般而言,如果我們是在多個子問題中選擇一個作為實施方案,而不會同時實施多個方案,那么子問題就是獨立的。

       7、考慮如何做備忘錄。

       8、分析所需時間是否滿足要求。

       9、寫出轉移方程式。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM