Dynamic Programming(動態規劃)

2021-09-25 05:37:05 字數 4056 閱讀 6326

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

動態規劃的核心是狀態及狀態轉移方程

y =d

p(x1

,x2,

x3,.

..xn

)y = dp(x1,x2,x3,...x_n)

y=dp(x

1,x2

,x3,

...x

n​)dp(

x1,x

2,x3

,...

,xn)

=kdp

(x11

,x12

,x13

,..x

1n).

..

dp(x_1,x_2,x_3,...,x_n) = kdp(x_11,x_12,x_13,..x_1n)...

dp(x1​

,x2​

,x3​

,...

,xn​

)=kd

p(x1

​1,x

1​2,

x1​3

,..x

1​n)

...確定狀態轉移方程需要明確

(1)自變數

確定決定每種狀態的變數有幾個

例如座標中的x,y等

(2)因變數的意義

即 dp(x1,x2,x3,…x_n)的含義

(3)狀態如何變化

即當前狀態與其他狀態之間的關係

具體如何實施和把握,我們通過下面的題目來探索

在這裡借用leetcode上關於動態規劃的幾個題,談一些自己的見解。在這裡和大家一起share。

按照我自己的理解,我循序漸進得通過幾個例子談一下動態規劃

乙個機械人位於乙個 m x n 網格的左上角 (起始點在下圖中標記為「start」 )。

機械人每次只能向下或者向右移動一步。機械人試圖達到網格的右下角(在下圖中標記為「finish」)。

問總共有多少條不同的路徑?

這是乙個簡單且經典的動態規劃(小學生都會做)問題。

根據上述方**,

(1)**(自變數)**我們可以假定(i,j)代表第i行,第j列

(2)**(因變數)**dp[i][j]表示start到(i,j)的路徑數量

注意:(1)(2)的合理選取至關重要,可能影響整個演算法的複雜度以及狀態轉移確定的難度

(3)**(狀態轉移)**dp[i][j]如何由前序狀態決定?

​ 分析具體問題發現

d p[

i][j

]=dp

[i−1

][j]

+dp[

i][j

−1

]dp[i][j] = dp[i - 1][j] + dp[i][j - 1]

dp[i][

j]=d

p[i−

1][j

]+dp

[i][

j−1]

在此之前,我們還必須明確

初始化狀態:

dp[0][0] = 1 dp[0][i] = 1 dp[i][0] = 1

變數細節控制

i - 1 > 0

j - 1 > 0

完成上述步驟,我們可以輕而易舉寫出這道題的**

public

intuniquepaths

(int m,

int n)

for(

int j =

1; j < m; j++

)//transfer

for(

int i =

1; i < m; i++)}

return dp[m -1]

[n -1]

;}

乙個機械人位於乙個 m x n 網格的左上角 (起始點在下圖中標記為「start」 )。

機械人每次只能向下或者向右移動一步。機械人試圖達到網格的右下角(在下圖中標記為「finish」)。

現在考慮網格中有障礙物。那麼從左上角到右下角將會有多少條不同的路徑?

這是problem one的乙個小變形,大家可以自行練習

只需要簡單修改狀態轉移即可。

即對存在(i,j)位置存在障礙物時,修改dp[i][j] = 0

public

intuniquepathswithobstacles

(int

obstaclegrid)

else

for(

int i =

1; i < n; i++

)else

}for

(int j =

1; j < m; j++

)else

}//transfer

for(

int i =

1; i < m; i++

)else}}

return dp[m -1]

[n -1]

;}

前面的題目當然都只是小試牛刀,現在加點難度

給定乙個整數陣列nums,找到乙個具有最大和的連續子陣列(子陣列最少包含乙個元素),返回其最大和。

我們依然嚴格執行我們的方**

(1)自變數是什麼?

不妨令(i,j)為從nums的第i個位置到第j個位置的子串行和

(2)因變數是什麼?

子串行和

(3)狀態怎麼轉移?

d p[

i][j

]=dp

[i][

j−1]

+num

s[j]

dp[i][j] = dp[i][j - 1] + nums[j]

dp[i][

j]=d

p[i]

[j−1

]+nu

ms[j

]初始化狀態

dp[0][0] = nums[0];

dp[i][i] = nums[i]

看到這,so easy!!!!!

但是不妨反思一下,這種做法的複雜度是**o(n^2)**吧

這個方法雖然******但會不會複雜度太高了呢??

顯然如果你在leetcode上使用這個複雜度的**提交,tle就會來到你身邊

因此,我們需要注意:動態規劃最大限度降低複雜的有效方法是

減少自變數數目

思考過後…

發現,其實自變數乙個就夠了

如果利用逐步求解,以連續陣列結束位置i為每一步的解,dp[i]記錄了以此位置作為子串行結束位置的最大和。

此時,我們需要的子串行一定是dp中最大的乙個。

事情就變得簡單了。

d p[

i]=m

ax

dp[i] = max\

dp[i]=

max因此,

public

intmaxsubarray

(int

nums)

}return maxnum;

}

未完待續…稍後更新新的題目

Prince and Princess 動態規劃

題目大意 求兩個序列的最長子序列 include include include includeusing namespace std int n,p,q const int maxn 250 250 int num1 maxn int hash maxn stack maxn int main i...

Colored Rectangles 動態規劃

題意 三種木棍,分別有 r對 g對 b對兩種不同木棍對可以弄移乙個矩形,要求矩形面積總和最大 思路 看題面,這種幾個變數互相影響並且最終目標固定的題目感覺就要用dp,而且資料比較小應該就是能用三維dp,雖然我比賽時沒做出來,但是我想的挺明白的,狀態轉移就是dp i j k max dp i 1 j ...

hdu1513 Palindrome 動態規劃

求讓乙個字串變為回文串所需最少插入字元數 定義狀態dp i j 表示從左到右i個字元,從右到左j個字元,要讓他們回文需要插入多少字元 顯然,a i a j 時,dp i j d p i 1 j 1 a i a j 時,就需要插入乙個字元,因此dp i j m in d p i 1 j dp i j ...