本文的內容部分引自:
我們遇到的問題中,有很大一部分可以用動態規劃(簡稱dp)來解。 解決這類問題可以很大地提公升你的能力與技巧,我會試著幫助你理解如何使用dp來解題。 這篇文章是基於例項展開來講的,因為乾巴巴的理論實在不好理解。
動態規劃演算法通常基於乙個遞推公式及乙個或多個初始狀態。當前子問題的解將由上一次子問題的解推出。使用動態規劃來解題只需要多項式時間複雜度, 因此它比回溯法、暴力法等要快許多。
現在讓我們通過乙個例子來了解一下dp的基本原理。
首先,我們要找到某個狀態的最優解,然後在它的幫助下,找到下乙個狀態的最優解
即大問題轉化成小問題,而小問題與大問題同質
如果我們有面值為1元、3元和5元的硬幣若干枚,如何用最少的硬幣湊夠11元? (表面上這道題可以用貪心演算法,但貪心演算法無法保證可以求出解,比如1元換成2元的時候)
好了,讓我們從最小的i開始吧。 當 i
=0,即我們需要多少個硬幣來湊夠0元。 由於1,3,5都大於0,即沒有比0小的幣值,因此湊夠0元我們最少需要0個硬幣。 (這個分析很傻是不是?別著急,這個思路有利於我們理清動態規劃究竟在做些什麼。) 這時候我們發現用乙個標記來表示這句「湊夠0元我們最少需要0個硬幣。」會比較方便, 如果一直用純文本來表述,不出一會兒你就會覺得很繞了。那麼, 我們用d(
i)=j
來表示湊夠i元最少需要j個硬幣。於是我們已經得到了d(
0)=0
, 表示湊夠0元最小需要0個硬幣。 當 i
=1時,只有面值為1元的硬幣可用, 因此我們拿起乙個面值為1的硬幣,接下來只需要湊夠0元即可,而這個是已經知道答案的, 即 d(
0)=0
。所以,
d(1
)=d(
1−1)
+1=d
(0)+
1=0+
1=1
當 i
=2時, 仍然只有面值為1的硬幣可用,於是我拿起乙個面值為1的硬幣, 接下來我只需要再湊夠2-1=1元即可(記得要用最小的硬幣數量),而這個答案也已經知道了。 所以
d(2
)=d(
2−1)
+1=d
(1)+
1=1+
1=2
一直到這裡,你都可能會覺得,好無聊, 感覺像做小學生的題目似的。因為我們一直都只能操作面值為1的硬幣!耐心點, 讓我們看看i=3時的情況。當 i
=3時,我們能用的硬幣就有兩種了:1元的和3元的( 5元的仍然沒用,因為你需要湊的數目是3元!5元太多了親)。 既然能用的硬幣有兩種,我就有兩種方案。如果我拿了乙個1元的硬幣,我的目標就變為了: 湊夠3-1=2元需要的最少硬幣數量。即
d(3
)=d(
3−1)
+1=d
(2)+
1=2+
1=3
這個方案說的是,我拿3個1元的硬幣;第二種方案是我拿起乙個3元的硬幣, 我的目標就變成:湊夠3-3=0元需要的最少硬幣數量。即d(
3)=d
(3−3
)+1=
d(0)
+1=0
+1=1
這個方案說的是,我拿1個3元的硬幣。好了,這兩種方案哪種更優呢? 記得我們可是要用最少的硬幣數量來湊夠3元的。所以, 選擇d(
3)=1
,怎麼來的呢?
具體是這樣得到的:d
(3)=
min
所以得到的狀態轉移方程是:d(
i)=m
in其中 i−
vj>=
0 ,vj
表示第
j 個硬幣的面值;
與數學分析結果的對比:
上面討論了乙個非常簡單的例子。現在讓我們來看看對於更複雜的問題, 如何找到狀態之間的轉移方式(即找到狀態轉移方程)。 為此我們要引入乙個新詞叫遞推關係來將狀態聯絡起來(說的還是狀態轉移方程)
ok,上例子,看看它是如何工作的。
乙個序列有n個數:a[
1],a
[2],
…,a[
n],求出最長非降子串行的長度。
為了方便理解我們是如何找到狀態轉移方程的,我先把下面的例子提到前面來講。 如果我們要求的這n個數的序列是:
5,3,4,8,6,7根據上面找到的狀態,我們可以得到:(下文的最長非降子串行都用lis表示)
•前1個數的lis長度d(
1)=1
(序列:5)
•前2個數的lis長度d(
2)=1
(序列:3;3前面沒有比3小的)
•前3個數的lis長度d(
3)=2
(序列:3,4;4前面有個比它小的3,所以d(3)=d(2)+1)
•前4個數的lis長度d(
4)=3
(序列:3,4,8;8前面比它小的有3個數,所以 d(
4)=m
ax+1
=3
ok,分析到這,我覺得狀態轉移方程已經很明顯了,如果我們已經求出了d(1)到d(i-1), 那麼d(i)可以用下面的狀態轉移方程得到:d(
i)=m
ax,其
中ja[j]
<=a[
i]用大白話解釋就是,想要求d(i),就把i前面的各個子串行中, 最後乙個數不大於a[i]的序列長度加1,然後取出最大的長度即為d(i)。 當然了,有可能i前面的各個子串行中最後乙個數都大於a[i],那麼d(i)=1, 即它自身成為乙個長度為1的子串行。
與數學分析結果的對比:
動態規劃 資料結構與演算法學習
求最值窮舉 重疊子問題 暴力窮舉效率低下 最優子結構 通過子問題最值得到原問題最值 狀態轉移方程 正確的窮舉 明確 狀態 定義dp陣列 函式的意義 明確 選擇 明確base case fibnacci數列 遞迴 intfib int n 備忘錄解法,自頂向下 intfib int n inthelp...
資料結構與演算法學習筆記
演算法基礎篇 第一章 演算法概述 首先了解一下基本的概念 1.1 什麼是演算法呢?從字面意義上理解,演算法就是用於計算的方法,用這種方法達到預期的結果。通俗的講,演算法可以理解為乙個完整的解題步驟,由一些基本的運算和規定的運算順序組成。通過這樣的解題步驟可以解決特定的問題。演算法可以抽象出5個特徵 ...
演算法學習筆記 動態規劃
在現實生活中,有一類活動的過程,由於它的特殊性,可將過程分成若干個互相聯絡的階段,在它的每一階段都需要作出決策,從而使整個過程達到最好的活動效果。因此各個階段決策的選取不能任意確定,它依賴於當前面臨的狀態,又影響以後的發展。當各個階段決策確定後,就組成乙個決策序列,因而也就確定了整個過程的一條活動路...