DP動態規劃介紹

動態規劃(dynamic programming)是運籌學的一個分支,是求解決策過程(decision process)最優化的數學方法。20世紀50年代初美國數學家R.E.Bellman等人在研究多階段決策過程(multistep decision process)的優化問題時,提出了著名的最優化原理(principle of optimality),把多階段過程轉化爲一系列單階段問題,利用各階段之間的關係,逐個求解,創立了解決這類過程優化問題的新方法——動態規劃

動態規劃算法通常基於一個遞推公式和n個初始狀態。當前子問題的解將由前子問題的解推出。使用動態規劃來解題只需要多項式時間複雜度。

基本思想

動態規劃算法通常用於求解具有某種最優性質的問題。在這類問題中,可能會有許多可行解。每一個解都對應於一個值,我們希望找到具有最優值的解。與分治法類似,基本思想也是將待求解問題分解成若干個子問題,先求解子問題,然後從這些子問題的解得到原問題的解。

與分治法不同的是,適合於用動態規劃求解的問題,經分解得到子問題往往不是互相獨立的。若用分治法來解這類問題,則分解得到的子問題數目太多,有些子問題被重複計算了很多次。如果我們能夠保存已解決的子問題的答案,而在需要時再找出已求得的答案,這樣就可以避免大量的重複計算。可以用一個表來記錄所有已解的子問題的答案。不管該子問題以後是否被用到,只要它被計算過,就將結果記錄下來,方便之後使用。這就是動態規劃法的基本思路。

動態規劃程序設計是對解最優化問題的一種途徑、一種方法,而不是一種特殊算法。不像搜索或數值計算那樣,具有一個標準的數學表達式和明確清晰的解題方法。動態規劃程序設計往往是針對一種最優化問題,由於各種問題的性質不同,確定最優解的條件也互不相同,因而動態規劃的設計方法對不同的問題,有各具特色的解題方法,而不存在一種萬能的動態規劃算法,可以解決各類最優化問題。

適用條件

  • 最優化原理(最優子結構性質)

最優化原理可這樣闡述:一個最優化策略具有這樣的性質,不論過去狀態和決策如何,對前面的決策所形成的狀態而言,餘下的諸決策必須構成最優策略。簡而言之,一個最優化策略的子策略總是最優的。一個問題滿足最優化原理又稱其具有最優子結構性質。

  • 無後效性

將各階段按照一定的次序排列好之後,對於某個給定的階段狀態,它以前各階段的狀態無法直接影響它未來的決策,而只能通過當前的這個狀態。換句話說,每個狀態都是過去歷史的一個完整總結。這就是無後向性,又稱爲無後效性。

  • 子問題的重疊性

動態規劃將原來具有指數級時間複雜度的搜索算法改進成了具有多項式時間複雜度的算法。其中的關鍵在於解決冗餘,這是動態規劃算法的根本目的。動態規劃實質上是一種以空間換時間的技術,它在實現的過程中,不得不存儲產生過程中的各種狀態,所以它的空間複雜度要大於其它的算法。

經典問題

有面值爲1元、3元和5元的硬幣若干枚,如何用最少的硬幣湊夠x元?

我們最先想到的算法一般是貪婪算法,每次減去能夠減掉的最大數值,最後得出結果。

當然這在上面問題這種問題上是成立的,因爲有面值是基數1元,這顯然不能代表普遍性。當提供的面值是2、3、5時,要求x=11,我們發現直接粗暴地套用貪婪原理並不奏效,x-5-5=1,此時無法進行下一步,需要提供回溯。

所以說,在有些時候這類問題可以通過貪婪算法解決,但是大部分情況,我們無法直接獲得想要的結果。

很明顯,這個問題可以分解爲:

求解湊齊x-1數值的硬幣枚數+1

求解湊齊x-3數值的硬幣枚數+1

求解湊齊x-5數值的硬幣枚數+1

最終的結果就是這三種情況的最小值,而這三種情況又可以繼續分別分解。解決的路徑跟遞歸很相似,但是相當容易套圈~

所以我們開始嘗試順人類認知的從小數值遞推到x.

現在我們在開始看上一部分DP適用條件

  • 最優化原理

  • 無後效性

  • 子問題的重疊性

第一個條件顯而易見的符合,第二個條件,當我們求出x-1x-3x-5這些結果之後,這些步驟的最終結果只是爲了能夠得到x的最優解,求解之後跟x+1x+3後續再無瓜葛,這就符合了無後效性。第三個條件,從我開始分解這道問題的時候就能夠得出結論。

解決

術語介紹

按照DP的知識,有下面幾個重要的術語:

  • 階段:把所給求解問題的過程恰當地分成若干個相互聯繫的階段,以便於求解,過程不同,階段數就可能不同.描述階段的變量稱爲階段變量。在多數情況下,階段變量是離散的,用k表示。此外,也有階段變量是連續的情形。如果過程可以在任何時刻作出決策,且在任意兩個不同的時刻之間允許有無窮多個決策時,階段變量就是連續的

  • 狀態:狀態表示每個階段開始面臨的自然狀況或客觀條件,它不以人們的主觀意志爲轉移,也稱爲不可控因素。在上面的例子中狀態就是某階段的出發位置,它既是該階段某路的起點,同時又是前一階段某支路的終點。

  • 決策:一個階段的狀態給定以後,從該狀態演變到下一階段某個狀態的一種選擇(行動)稱爲決策。在最優控制中,也稱爲控制。在許多問題中,決策可以自然而然地表示爲一個數或一組數。不同的決策對應着不同的數值。描述決策的變量稱決策變量,因狀態滿足無後效性,故在每個階段選擇決策時只需考慮當前的狀態而無須考慮過程的歷史。決策變量的範圍稱爲允許決策集合

  • 策略:由每個階段的決策組成的序列稱爲策略。對於每一個實際的多階段決策過程,可供選取的策略有一定的範圍限制,這個範圍稱爲允許策略集合。允許策略集合中達到最優效果的策略稱爲最優策略。

  • 狀態轉移方程:給定k階段狀態變量x(k)的值後,如果這一階段的決策變量一經確定,第k+1階段的狀態變量x(k+1)也就完全確定,即x(k+1)的值隨x(k)和第k階段的決策u(k)的值變化而變化,那麼可以把這一關係看成(x(k),u(k))與x(k+1)確定的對應關係,用x(k+1)=Tk(x(k),u(k))表示。這是從k階段到k+1階段的狀態轉移規律,也就是狀態轉移方程。

狀態

上面在Encyclopedia上提到的解讀可能比較抽象,狀態就是問題分解得到子問題的當前解。

具體到這個例子,就是當x=[0、1、2、3、4、5、6、7、8、9、...x-1、x]這些問題的解。

我們通過基礎的數據結構數組S表示子問題解,也就是原來問題的狀態。

  • s[0]

求解需要多少枚硬幣可以湊齊0元,顯然,s[0]=0

  • s[1]

需要多少枚硬幣可以湊齊1元,s[1]=1,需要1枚1元硬幣

  • s[2]

需要多少枚硬幣可以湊齊2元,s[2]=s[2-1]+1=s[1]+1=2。需要上面子問題狀態再加上1枚1元硬幣

  • s[3]

需要多少枚硬幣可以湊齊3元,此時的情況就比較複雜了。我們有兩種選擇,當然是基於原來的狀態求出。

  1. 以s[2]的狀態基礎在加一枚1元硬幣。s[3]=s[3-1]+1

  2. 以s[0]的狀態再加一枚3元硬幣。s[3]=s[3-3]+1

現在的問題就是如何確定所有選擇。從前面的疾苦==記錄可以看出,我都是有意識的在下標上做文章,故意將s[0]===s[3-3],這就是關鍵。每次我們獲取當前狀態,不是要從緊鄰的上一個狀態遞推,而是根據提供給我們的硬幣數值得到可能湊到當前數值的情況。

2元再加一枚1元硬幣是如此,0元再加一枚3元硬幣也是如此。當要求解s[5]的時候情況更加多變。候選變成了[s[4]+1,s[2]+1,s[0]+1]。每個子問題的求解都要嘗試可能的求解路徑狀態。

4+1是一種情況,2+3、0+5是另外的情況。

那麼s[3]的結果是哪一個呢,根據問題需要求解最小的硬幣枚數,顯然結果是Min(s[2]+1,s[0]+1),是s[3]=1,需要1枚三元硬幣

  • s[4]

需要多少枚硬幣可以湊齊4元,s[4]=Min(s[3]+1,s[1]+1),s[4]=2,需要一枚3元硬幣的基礎上再加一枚1元硬幣。

上面在s[3]的求解過程中,實際上已經脫出了該問題的狀態轉移方程。

s[x]=Min(s[x-j]+1),其中j是提供的硬幣面值。

實現

x=input('plz input the value of x')
s=np.arange(int(x))
x_coins=(1,3,5)
for item in range(1,x-1):
    for i in x_coins:
        if item>=i and s[item-i]+1<s[item]:
            s[item]=s[item-i]+1
print(s)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章