動態規劃是一種高效的演算法。在數學和電腦科學中,是一種將複雜問題的分成多個簡單的小問題思想 ---- 分而治之。因此我們使用動態規劃的時候,原問題必須是重疊的子問題。運用動態規劃設計的演算法比一般樸素演算法高效很多,因為動態規劃不會重複計算已經計算過的子問題。因為動態規劃又可以稱為「記憶化搜尋」。
01揹包是介紹動態規劃最經典的例子,同時也是最簡單的乙個。我們先看看01揹包的是什麼?
[plain]view plain
copy
問題(01揹包):
有n個重量和價值分別為wi和vi的物品。從這些物品中挑出總重量不超過w的物品,求所有挑選方案中價值總和的最大值。
這就是被稱為01揹包的問題。在沒學習動態規劃之前,我們看到這個問題第一反應會用dfs搜尋一遍。那我們先使用這種方法來求解01揹包問題:
[cpp]view plain
copy
//n,w 如題意所述
intw, n;
//w[i]和v[i]分別表示wi,vi
intw[maxn], v[maxn];
//從第i個物品開始挑選總重量小於j的部分
intdfs(
inti,
intj)
乍一看dfs好像就可以解決這個問題,那還有動態規劃什麼事。然而我們仔細分析一下時間複雜度,每一種狀態都用選或者不選兩種可能。所以我們可以得出使用dfs的時間複雜度為o(2^n)。顯然這個方法不是乙個很好的方法,因為這個時間複雜度太高了。我們仔細研究可以發現,造成時間複雜度這麼高的原因是重複計算。既然我們找到複雜度這麼高的原因,那我們就可以想辦法減少它重複計算的次數。仔細分析容易想到,使用乙個二維陣列來記錄每一次搜尋的答案,這樣我們就避免了重複計算。
[cpp]view plain
copy
//n,w 如題意所述
intw, n;
//w[i]和v[i]分別表示wi,vi
intw[maxn], v[maxn];
//儲存每一次搜尋的答案
//初始化dp陣列的值,使其全為-1
intdp[maxn][maxn];
//從第i個物品開始挑選總重量小於j的部分
intdfs(
inti,
intj)
這樣的小技巧,我們稱之為記憶化搜尋。我們只是小小的改變就讓它的時間複雜度降低至o(nw)。
仔細分析,可以發現我們還可以有更簡單的寫法:
[cpp]view plain
copy
//dp[i+1][j] 表示從前i個物品挑選出總重量超過j的物品時,揹包中的最大價值
void
solve()
} }
使用遞推方程直接求解的方法,我們稱之為dp。因為他每一次的選取,都在動態的計算最優的情況。當然可能他區域性不是最優,但是整體一定是最優解。這就是他和貪心演算法最大的不同,貪心演算法,每一次都是最優,但是整體不一定不是最優。附上一道習題:
hdu2602bone collector
動態規劃 01揹包與記憶化搜尋
動態規劃是一種高效的演算法。在數學和電腦科學中,是一種將複雜問題的分成多個簡單的小問題思想 分而治之。因此我們使用動態規劃的時候,原問題必須是重疊的子問題。運用動態規劃設計的演算法比一般樸素演算法高效很多,因為動態規劃不會重複計算已經計算過的子問題。因為動態規劃又可以稱為 記憶化搜尋 01揹包是介紹...
01揹包 (記憶化搜尋 動態規劃 一維陣列)
有n件物品,第i件物品的重量是w i 它的價值是v i 每件物品數量只有乙個,現在給你個承重為c的揹包,如何讓揹包裡裝入的物品具有最大的價值?1.暴力遞迴 遇到動態規劃問題寫不出來的話就寫暴力遞迴 int maxprix vector int w,vector int v,int c,int i 這...
動態規劃 記憶化搜尋
記憶化搜尋顧名思義是在搜尋的過程中通過記錄搜尋的中間狀態從而達到減少重複搜尋的方法,通常用在搜尋樹 現重複子節點的情況。例題 滑雪 給定乙個r行c列的矩陣,表示乙個矩形網格滑雪場。矩陣中第 i 行第 j 列的點表示滑雪場的第 i 行第 j 列區域的高度。乙個人從滑雪場中的某個區域內出發,每次可以向上...