什麼是動態規劃?
動態規劃(dynamic programming)是通過組合子問題的解來解決問題的。動態規劃是用於求解包含重疊子問題的最優化問題的方法。其基本思想是,將原問題分解為相似的子問題。在求解的過程中通過子問題的解求出原問題的解。
動態規劃的分類:
1. 線性規劃:攔截飛彈,合唱隊形,挖地雷等。
2. 區域規劃:石子合併,加分二叉樹,統計單詞個數等。
3. 樹形動規:貪吃的九頭龍,二分查詢樹,聚會的歡樂等。
4. 揹包問題:01揹包問題,完全揹包問題,分組揹包問題,裝箱問題,擠牛奶等
5. 除此之外還有插頭dp,按位dp,狀態壓縮dp等等。
入門題目:數字三角形
題目描述:給出了乙個數字三角形。從三角形的頂部到底部有很多條不同的路徑。對於
每條路徑,把路徑上面的數加起來可以得到乙個和,你的任務就是找到最大的和。
如:3 8
8 1 0
2 7 4 4
4 5 2 6 5
分析一下為什麼不能使用貪心演算法,即每一次走都走下一行的兩個數值較大的。因為有可能在某一步的時候數值小沒走到,但是該路徑下面有較大的數值,就不會走到,就得不到最大的值。
1.樸素dfs搜尋演算法
可以採用樸素的深度優先搜尋演算法,即樸素dfs。每一次走都分為兩步,第一步求出走下一步時走的最大值,然後加上此步的數值。
int dfs(int x,int y) //表示從第x行,第y個數往下走可以得到的最大價值和,dfs(0,0)即為本題解。
完整的**示例為:
#includeusing
namespace
std;
int num[5][5] = ;
int numcount = 5;
int dfs(int x,inty)
intmain()
這個演算法效率極低,為什麼呢?因為其中有大量的重複計算。通常遞迴都會有大量的重複計算。
2.dfs+記憶化搜尋方法
針對於上述dfs演算法的重複計算,我們可以先將dfs(x,y)的結果儲存起來,等到下次需要時,直接使用。這就是記憶化搜尋。
int dfs(int x,inty)
完整的**示例為:
#includeusing
namespace
std;
int num[5][5] = ;
int numcount = 5
;int result[5][5];
int dfs(int x,inty)
intmain()
不論是dfs還是記憶化dfs都是基於遞迴的思想進行計算。總結一下實際操作的特點。
(1)搜尋的引數只有(x,y),每一對(x,y)確定乙個狀態。
(2)搜搜的轉移是從(x+1,y)和(x+1,y+1)到(x,y)的,意思就是我們通過(x+1,y)和(x+1,y+1)的解去求(x,y)。
於是,設想:如果不用dfs,直接用陣列儲存狀態,在狀態與狀態之間實現轉移。
for(int i = numcount - 1; i >= 0; i--)for(int j = 0;j <= i; j++)
result[i][j] = max(result[i+1][j],result[i+1][j+1]) + num[i][j];
完整的程式示例為:
#includeusing
namespace
std;
int num[5][5] = ;
int numcount = 5
;int result[6][6];
intmain()
總結:搜尋的引數只有(x,y)。每一對(x,y)確定乙個狀態。我們通過(x+1,y)和(x+1,y+1)的解去求(x,y),於是我們可以設計出狀態並明確狀態的轉移,從而寫出狀態轉移方程。這就是動態規劃!!!!
摘自:
dfs 記憶化 滑雪
傳送門 題意 給定乙個r行c列的矩陣,表示乙個矩形網格滑雪場。矩陣中第 i 行第 j 列的點表示滑雪場的第 i 行第 j 列區域的高度。乙個人從滑雪場中的某個區域內出發,每次可以向上下左右任意乙個方向滑動乙個單位距離。當然,乙個人能夠滑動到某相鄰區域的前提是該區域的高度低於自己目前所在區域的高度。資...
滑雪 DFS 記憶化搜尋
michael喜歡滑雪百這並不奇怪,因為滑雪的確很刺激。可是為了獲得速度,滑的區域必須向下傾斜,而且當你滑到坡底,你不得不再次走上坡或者等待公升降機來載你。michael想知道載乙個區域中最長的滑坡。區域由乙個二維陣列給出。陣列的每個數字代表點的高度。下面是乙個例子 1 2 3 4 5 16 17 ...
帕斯卡遊記 記憶化dfs
問題描述 nxn遊戲板上裝有整數,每平方乙個非負整數。目標是沿著板子的左上角到右下角的任何合法路徑行進。任何乙個正方形中的整數表示距該位置必須多大的步幅。如果步長將提前離開遊戲板,則禁止沿該特定方向前進。所有步驟都必須在右側或底部。請注意,0是乙個死角,會阻止進一步的進展。考慮圖1所示的4 x 4板...