一步步解讀動態規劃 合唱團

2022-03-11 19:58:33 字數 3314 閱讀 6744

我們為了能說清楚動態規劃的思路,下面先簡化下合唱團的題:

1、明確問題的目標是:

(1)求k個數的最大乘積

(2)相鄰索引值差<=d

2、分解問題:

為了求解方便,我們來定個標準,根據k個數的末尾元素把目標問題分為以下n種情況

對以上n種情況比較結果,最後選取最大乘積輸出,就是我們要求的目標值了。不過這樣我們還需要求出每個結束元素前的k-1個數的最大乘積,這個新問題是不是似曾相識呢?求k-1個數的最大乘積同樣又可以以剛才分析的方式去思考,以末尾元素為標準分為幾種情況。

那麼現在看來為了求目標問題,我們需要明確兩個變數的值,乙個是末尾元素,另乙個是前k-1個最大乘積。因為我們求 k 個數最大乘積依賴於末尾元素和前k-1個數的最大乘積兩個因素。我們定義乙個二維陣列q,行 i 代表末尾元素的索引值,列 j 代表長度。q[i][j] 表示以 a[i] 為末尾元素,長度為 j+1 的最大乘積值。是不是有點抽象了,沒關係,接下來會一目了然的。

3、我們先拿個例子走下流程:a[5] = [4,5,2,1,7],k=3,d=2

狀態陣列q:

j=  0   1  2

i=0  [ [   4                     ]

i=1    [   5  20        ]

i=2    [   2  10  40  ]

i=3    [   1  5  20  ]

i=4    [   7  14  70  ] ]

(1)先找到初始狀態,k=1時,末尾元素為a[i],即q[i][0] = a[i],填充 q 陣列。

(2)別忘了,我們有個約束條件,相鄰索引值差<=d。假設長度為k的末尾元素索引值為i,它之前長度k-1的最後乙個元素索引為p,那麼 i-p<=d=2,即 max(i-2,0)=

(3)有了初始狀態,目標值還會遠嗎?

接下來看長度 k =2的情況 (即j=1,依賴於j=0的最大乘積和末尾元素),末尾元素為 a[0],長度只能為1,排除。

末尾元素為 a[1],前乙個元素索引範圍 0=

末尾元素為 a[2],前乙個元素索引範圍 0=

末尾元素為 a[3],前乙個元素索引範圍 1=

末尾元素為 a[4],前乙個元素索引範圍 2=

(4)加油,還差一點點,你就成功了。

接下來看長度 k =3 (即j=2,依賴於j=1的最大乘積和末尾元素),末尾元素為 a[0],長度只能為1,排除。

末尾元素為 a[1],長度最多為2,排除。

末尾元素為 a[2],前乙個元素索引範圍 0=

末尾元素為 a[3],前乙個元素索引範圍 1=

末尾元素為 a[4],前乙個元素索引範圍 2=

以上我們把狀態陣列q全部求出來了,不要因為走的太遠而忘記為什麼出發,我們的目標是比較末尾元素為a[i]的長度為k的最大乘積。那就比較q[i][2],得出70是以a[4]為末尾元素的長度為3的最大乘積。大致的思路就是這些了,原來求 k 個數的最大乘積要回溯到 k=1 時初始狀態一步步求解啊。

搞明白了思路,**也就出來了。就這個例子而言,**如下:

1

#coding:utf-8

2 a = [4,5,2,1,7]

3 k = 3

4 d = 2

5 n =len(a)

6 q = [[0 for j in range(k)] for i in

range(n)]7#

j代表列 i代表行 對狀態陣列q賦值

8 value =0

9for j in

range(k):

10for i in

range(n):11#

初始化第0列

12if j ==0:

13 q[i][j] =a[i]

14continue

15for l in range(max(0,i-d),i):

16 q[i][j] = max(q[i][j], q[l][j-1]*a[i])

17if j == k-1:

18 value =max(value, q[i][j])

19print value

4、下面我們來總結動態規劃

實際上動態規劃問題都可以用遞迴來求解,不過遞迴的時候會求重複項並且造成棧溢位問題,所以我們借助狀態陣列把每個狀態(遞迴返回值 )記錄下來,用自底而下的思想去求解目標問題,從遞迴的邊界條件出發求得動態規劃的初始狀態,然後一步步求解目標,相當於遞迴的逆過程。

動規解題的一般思路

(1) 原問題分解為子問題

(2)確定狀態

整個問題的時間複雜度是狀態數目乘以計算每個狀態所需時間。

(3)確定一些初始狀態(邊界狀態)的值

以上面為例,就是求解q陣列第一列的值。

(4) 確定狀態轉移方程

定義出什麼是「狀態」,以

及在該「狀態」下的「值」後,就要找出不同的狀態之間如何遷移――即如何從乙個或多個「值」已知的 「狀態」,求出另乙個「狀態」的「值」(遞推型)。狀態的遷移可以用遞推公式表示,此遞推公式也可被稱作「狀態轉移方程」。

特點:1>問題具有最優子結構性質。如果問題的最優解所包含的子問題的解也是最優的,我們就稱該問題具有最優子結構性質。

2>無後效性。當前的若干個狀態值一旦確定,則此後過程的演變就只和這若干個狀態的值有關,和之前是採取哪種手段或經過哪條路徑演變到當前的這若干個狀態,沒有關係。

引申:想到hmm裡的維特比演算法也是利用動態規劃求解最短路徑,有必要再加強學習下!

參考:

一步步學ROS

最近因為看svo的 裡面用到catkin決定要好好看ros,年前學會基本操作。啟動節點 rosrun package name executable name 檢視節點 rosnode list 注 rosout 節點是乙個特殊的節點,通過 roscore 自動啟動 檢視特定節點的資訊 rosnod...

windows Thrift c 一步步搭建

1.thrift 原始碼路徑 2.libevent原始碼路徑 3.boost路徑 安裝 conan install boost 1.68.0 conan stable 4.openssl路徑 安裝 conan install openssl 1.1.1a conan stable conan安裝bo...

一步步啟動linux

可以一步一步啟動linux.在ubantu剛一啟動時,按c健即進入grub 提示符狀態,在此狀態下輸入 我用的是ubuntu 13 grub linux vmlinuz grub ls boot grub initrd boot initrd.img 3.11.0 15 generic grub b...