灯神动态规划(Dynamic Programing)学习笔记 打劫问题 凑整问题 背包问题 例题+原理+源码超详细讲解
動(dòng)態(tài)規(guī)劃Dynamic Programing學(xué)習(xí)筆記 打劫問(wèn)題 湊整問(wèn)題 背包問(wèn)題
- 學(xué)習(xí)資源
- Example1. 打家劫舍問(wèn)題 looting problem
- Example2. 湊整問(wèn)題
- Example3. 背包問(wèn)題
學(xué)習(xí)資源
燈神的視頻是我目前個(gè)人覺(jué)得講解最清晰的動(dòng)態(tài)規(guī)劃教學(xué),這篇文章是對(duì)他視頻內(nèi)容的匯總,在此基礎(chǔ)上我還個(gè)人補(bǔ)充了背包問(wèn)題的解決方案。
燈神的b站小課堂
Example1. 打家劫舍問(wèn)題 looting problem
題目模型簡(jiǎn)化如下: 給定數(shù)組arr=[4,1,1,9,1],從中選擇數(shù)字來(lái)使得總和最大,注意不能選擇相鄰的數(shù)字。例如,選擇4后,不能選擇1;選擇9后,不能選擇9左右兩側(cè)的數(shù)字1。
模型建立。我們拿出一組新的數(shù)組arr=[1,2,4,1,7,8,3],將其按順序分別編號(hào)為0-6。如圖
假定opt(6)表示:從前6個(gè)數(shù)字中選出總和最大的最佳方案(也就是我們期望得到的結(jié)果),同理opt(5)表示從前五個(gè)數(shù)字中選出來(lái)總和最大的方案……依次類推。
我們?cè)谶@個(gè)基礎(chǔ)上進(jìn)行推理:對(duì)于第六個(gè)數(shù)字,我們有選擇和不選擇這兩種操作,當(dāng)我們選擇第六個(gè)數(shù)時(shí),根據(jù)規(guī)則就無(wú)法選擇第五個(gè)數(shù)字,因此opt(6)=opt(4)+arr[6],即在這種情況下,opt6的值等于前四個(gè)數(shù)字中選出的最大值加上第六個(gè)數(shù)的數(shù)值。如果我們不選擇第六個(gè)數(shù),那么opt(6)=opt(5),即前五個(gè)數(shù)所能選出總和最大的值。
根據(jù)這個(gè)邏輯,為了算出opt6,我們需要經(jīng)歷以下過(guò)程。加號(hào)表示選擇當(dāng)前數(shù),減號(hào)表示不選擇當(dāng)前數(shù)。整個(gè)過(guò)程的樹(shù)狀圖如下根據(jù)上圖所示的邏輯,我們可以從中推出普遍的遞推規(guī)律。因?yàn)槲覀兪乔笞畲笾?#xff0c;所以前i個(gè)數(shù)字所能構(gòu)成的最大總和為opt(i)=max(opt(i-1),opt(i-2)+arr[i]),其中,opt(i)是我們放棄選擇第i個(gè)數(shù)時(shí)所得到的前i-1個(gè)數(shù)能構(gòu)成的最大值;opt(i-2)+arr[i] 是我們選擇第i個(gè)數(shù)時(shí)能得到的最大值。
尋找出口條件:#當(dāng)i=0時(shí) opt(1)=max(arr[1],arr[0]) #當(dāng)i=1時(shí) opt(0)=arr(0)
用代碼來(lái)實(shí)現(xiàn)當(dāng)前邏輯。分兩種,首先是recursive method
運(yùn)行這段代碼后可以發(fā)現(xiàn)最終結(jié)果為15。這個(gè)地方我們運(yùn)行的基本原理就是在函數(shù)中不停地調(diào)用自身,最終由opt6出發(fā)推演至opt0,直到算出答案(如上面我手繪的樹(shù)狀圖)。這種辦法雖然變成起來(lái)思路比較直觀,但在該推演過(guò)程中有很多重復(fù)的運(yùn)算。回到上面的樹(shù)狀圖,該辦法在計(jì)算opt6時(shí),重復(fù)計(jì)算了opt4和opt3,我分別用黃色、綠色熒光筆將重復(fù)部分標(biāo)記了起來(lái)。
當(dāng)arr內(nèi)數(shù)據(jù)和i的數(shù)量變大時(shí),使用這種辦法的運(yùn)算成本將大幅升高。接下來(lái)介紹非recursive的計(jì)算方法:
#續(xù)上面的代碼 def nonrec_method(arr):opt = np.zeros(len(arr)) #建立數(shù)組來(lái)存儲(chǔ)opt數(shù)據(jù)opt[0]=arr[0]opt[1]=max(arr[1],arr[0])for i in range(2,len(arr)):A = opt[i-2]+arr[i]B = opt[i-1]opt[i] = max(A,B)return opt[len(arr)-1] nonrec_method(arr)輸出結(jié)果為15.0。該種方法可以理解為逆著樹(shù)狀圖,由opt0出發(fā)一步一步推演至最終結(jié)果opt6,好處在于每一步的結(jié)果我們都儲(chǔ)存在了數(shù)組中,節(jié)約了不少計(jì)算資源。
Example2. 湊整問(wèn)題
題目要求如下,給定數(shù)組arr=[3,34,4,12,5,2],判斷能否實(shí)用數(shù)組內(nèi)的數(shù)構(gòu)成S(s為一個(gè)數(shù))。
模型建立:假定S=9,將arr中的數(shù)據(jù)從0-5進(jìn)行編號(hào)。如圖
我們?cè)O(shè)subset(i,S),其中i表示使用前i個(gè)數(shù)字,S為我們期望拼湊成的數(shù)。例如,subset(5,9)表示使用前五個(gè)數(shù)字來(lái)拼湊出9的總和。subset(2,3)表示使用前兩個(gè)數(shù)字拼湊出3。我們從這個(gè)符號(hào)出發(fā),開(kāi)始推理過(guò)程,首先考慮subset(5,9),我們此時(shí)要用前五個(gè)數(shù)來(lái)拼出9,首先判斷第五個(gè)數(shù)。在這個(gè)地方我們有兩種選擇,第一種選擇是使用第五個(gè)數(shù)來(lái)拼湊出9,那么選擇后的情況就變成了subset(4,7),表示用前4個(gè)數(shù)去湊成7。第二種選擇是不使用第五個(gè)數(shù),那么情況就變成了subset(4,9)。繪制成樹(shù)狀圖如下
由此我們可以推出普遍的遞推規(guī)律,若使用前i個(gè)數(shù)湊成S,遞推規(guī)律表達(dá)式為其中arr表示存放數(shù)據(jù)的數(shù)組。
接下來(lái),我們開(kāi)始尋找出口條件,第一種情況是當(dāng)S下降為0時(shí),說(shuō)明前面的數(shù)字已經(jīng)完成了拼湊任務(wù),此時(shí)應(yīng)該返回True,表示能夠拼湊出S;第二種情況是當(dāng)i下降為0時(shí),S仍然不為0。i=0說(shuō)明已經(jīng)引導(dǎo)到了數(shù)組的首位數(shù),如果此時(shí)滿足arr[0]==S,那么說(shuō)明能夠湊出S,返回True。如果不相等則說(shuō)明arr中的數(shù)字無(wú)法拼成S,返回False。這兩個(gè)出口條件總結(jié)如下:
運(yùn)行后結(jié)果為True,說(shuō)明arr內(nèi)的數(shù)字能夠湊出9。
運(yùn)行后輸出結(jié)果同樣為True,但該方法中,我們使用numpy創(chuàng)建了一個(gè)數(shù)組,依次計(jì)算并存儲(chǔ)了各個(gè)階段中subset的bool值,避免了前面recursive method中出現(xiàn)的重復(fù)計(jì)算的問(wèn)題。本質(zhì)上,這種辦法相當(dāng)于創(chuàng)建了一個(gè)如下的bool表格:紅圈就是我們最終想要得到的結(jié)果,即`subset(5,9)
Example3. 背包問(wèn)題
總結(jié)
以上是生活随笔為你收集整理的灯神动态规划(Dynamic Programing)学习笔记 打劫问题 凑整问题 背包问题 例题+原理+源码超详细讲解的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。