動態規劃概念及例題分析

2021-08-29 14:11:57 字數 3535 閱讀 4220

解決問題的乙個重要思想就是歸納,即減小問題的規模。如果小規模在一定範圍內可解,則求解返回,若還是太大,繼續往小分解。在返回大問題的過程中,有個弊端,多個大問題與同乙個小問題有聯絡,這個小問題反覆求解。解決辦法就是動態規劃,存下這個小問題的解,不就省事多了。

維基百科說得好,動態規劃就是通過把原問題分解為相對簡單的子問題的方式求解複雜問題的方法。

說白了就是:

1. 這個問題可以分解為子問題

2. 原問題與子問題有關係

3. 子問題可以求解並記錄

說到這裡,你是不是想到了遞迴,想到了數學歸納法,其實他們都是相通的。(哇哦,瞬間覺得學科之間原來真的是有聯絡的)

看到這裡,你是不是覺得動態規劃挺簡單的嘛,就是三個步驟嘛:

1. 把原問題分解為子問題

2. 找到原問題與子問題的關係

3. 記錄下子問題的解

emmm,就是這三個簡單的步驟,難倒了多少好漢啊(也包括我),下面我們就通過分析一些使用動態規劃解決的問題來摸索這三步怎麼找。

動態規劃的常見應用:

1 1 2 3 5 8 13。。。

我們要求第n個數,即f(n)

a. 分解問題:求f(n)就是求f(n - 1) 與 f(n - 2)

b. 找關係:f(n) = f(n - 1) + f(n - 2)

c.找個陣列把f(n)存起來,這樣呼叫時就不用再次計算了

這樣,在f(1) 與 f(2) 已知的情況下,我們便可以求得f(n)。

看到這裡,你可能會說這不是明顯的遞迴嗎,怎麼是動態規劃呢?這裡便要提出動態規劃與遞迴的不同,若用遞迴,求f(100)就要求f(99) 與 f(98), 求f(99)就要求f(98) 與f(97),此時f(98)算了兩遍,而使用動態規劃,它儲存了f(98),後面用的時候便不需要再重新計算,能夠省下來許多時間,這便是傳說中動態規劃記憶化儲存的性質。

設f(n)為長度為n的鋼條切割後得到的最大價值

a.分解問題:

求f(n)即需要知道f(n - 1),f(n - 2), ....及p(n), p(n -1), p(n -2)....

b.找關係:

f(n) = max(p(n), f(1) + f(n -1), f(2) + f(n -2), ......., f(n/2) + f(n/2) )

c.儲存f(n),節省時間

這樣便可找到最值。

int cut(int p)

r[i]=q;

}return r[p.length];

}

在乙個夜黑風高的晚上,有n(n <= 50)個小朋友在橋的這邊,現在他們需要過橋,但是由於橋很窄,每次只允許不大於兩人通過,他們只有乙個手電筒,所以每次過橋的兩個人需要把手電筒帶回來,i號小朋友過橋的時間為t[i],兩個人過橋的總時間為二者中時間長者。問所有小朋友過橋的總時間最短是多少。

輸入:

兩行資料:第一行為小朋友個數n

第二行有n個數,用空格隔開,分別是每個小朋友過橋的時間。

輸出:

一行資料:所有小朋友過橋花費的最少時間。

a. 分解問題

i個人過河可看作是前i-1個人過河的情況再多乙個人,或是前i-2個人再做兩個人情況,這兩種的時間不一樣,需要分開討論。

b. 找關係

我們先將所有人按花費時間遞增進行排序,假設前i個人過河花費的最少時間為opt[i]。

(1)考慮前i-1個人過河的情況,即河這邊還有1個人,河那邊有i-1個人,並且這時候手電筒肯定在對岸,所以opt[i] = opt[i-1] + a[1] + a[i]        (讓花費時間最少的人把手電筒送過來,然後和第i個人一起過河)

(2)如果河這邊還有兩個人,乙個是第i號,另外乙個無所謂,河那邊有i-2個人,並且手電筒肯定在對岸,所以opt[i] = opt[i-2] + a[1] + a[i] + 2*a[2]    (讓花費時間最少的人把電筒送過來,然後第i個人和另外乙個人一起過河,由於花費時間最少的人在這邊,所以下一次送手電筒過來的一定是花費次少的,送過來後花費最少的和花費次少的一起過河,解決問題)

所以 opt[i] = min。

c.記錄每乙個opt[n], 節省時間。

#include#include#includeusing namespace std;

int main()

sort(child, child + childnum);

vectorvect(childnum);

vect[0] = 0;

vect[1] = child[1];

for (i = 2; i < childnum; i++)

cout << vect[childnum - 1];

return 0;

}

定義c[i][j]表示x[i]與y[j]的最大子串行的長度

其中x[i]表示a序列前i個

其中y[j]表示b序列前j個

algorithm lcs

input: a[n], b[n]

output: length

begin

int c[i][j]

for(i = 0; i <= n; i++)

for(i = 1; i <= n; i++)

else;}}

}end

最短公共超序列(scs)s定義為所有以t和p為子串行的序列中最短的乙個。

定義a[i][j]表示s1[i]與s2[j]的最大子串行的長度

其中s1[i]表示a序列前i個

其中s2[j]表示b序列前j個

end

動態規劃演算法在歸納的基礎上對數值小問題的解進行儲存,這樣可以在重複使用的時候減小開銷,一般動態規劃在解決日常問題時很常見。

動態規劃例題

題目描述 有一條很長的數軸,一開始你在0的位置。接下來你要走n步,第i步你可以往右走ai或者bi。問n步之後,0到m的每個位置,能不能走到?輸入格式 第一行,兩個整數n,m。接下來n行,每行兩個整數ai,bi。輸出格式 一行,一共m 1個數,每個數都是0或1表示能否走到,數字之間不用空格隔開。樣例輸...

《動態規劃》 ACM 動態規劃例題詳解

描述 7 3 8 8 1 0 2 7 4 4 4 5 2 6 5 圖1 圖1給出了乙個數字三角形。從三角形的頂部到底部有很多條不同的路徑。對於每條路徑,把路徑上面的數加起來可以得到乙個和,你的任務就是找到最大的和。注意 路徑上的每一步只能從乙個數走到下一層上和它最近的左邊的那個數或者右邊的那個數。輸...

動態規劃及其動態規劃經典例題

動態規劃是最重要 最經典的演算法之一,學好動態規劃對我們十分重要,掌握動態規劃對解決某些問題會起到事半功倍的效果。特點 可以把原始問題劃分為一系列子問題 求解每個子問題僅一次,並將其結果儲存到乙個表中,以後用到時直接訪問,不重複計算,節省時間。自底向上地計算 適用範圍 原問題可以分為多個相關子問題,...