目錄
1 DP理論
1.1 簡介
動態規劃(dynamic programming)是運籌學的一個分支,是求解決策過程(decision process)最優化的數學方法。
20世紀50年代初美國數學家R.E.Bellman等人在研究多階段決策過程(multistep decision process)的優化問題時,提出了著名的最優化原理(principle of optimality),把多階段過程轉化爲一系列單階段問題,利用各階段之間的關係,
逐個求解,創立了解決這類過程優化問題的新方法——動態規劃。整個動態規劃,重點是找到轉態轉移方程。
做了實例之後發現,轉移方程雖然是重點,卻不是難點,狀態轉移的前提是知道啥是狀態。不同的場景的建模方式不同,有些場景狀態規律比較隱晦,或者說就是不太容易找到一個契合的定義。
1.2 基本思想
若要解一個給定問題,我們需要解其不同部分(即子問題),再合併子問題的解以得出原問題的解。 通常許多子問題非常相似,爲此動態規劃法試圖僅僅解決每個子問題一次,從而減少計算量: 一旦某個給定子問題的解已經算出,則將其記憶化存儲,以便下次需要同一個子問題解之時直接查表。 這種做法在重複子問題的數目關於輸入的規模呈指數增長時特別有用。
1.3 適用場景
動態規劃常常適用於有重疊子問題和最優子結構性質的問題。
1.4 其他
DP和分治的區別:
共同點:二者都要求原問題具有最優子結構性質,都是將原問題分而治之,分解成若干個規模較小(小到很容易解決的程序)的子問題.然後將子問題的解合併,形成原問題的解.
不同點:分治法將分解後的子問題看成相互獨立的,通過用遞歸來做。
動態規劃將分解後的子問題理解爲相互間有聯繫,有重疊部分,需要記憶,通常用迭代來做。
2 DP實例
2.1 楊輝三角
略與2.2基本一樣
2.2矩陣取數問題
一個N*N矩陣中有不同的正整數,經過這個格子,就能獲得相應價值的獎勵,從左上走到右下,只能向下向右走,求能夠獲得的最大價值。例如:3 * 3的方格。
1 3 3
2 1 3
2 2 1
就是求到右下點的途徑的路徑的最大值。從遞推的思想看,
右下角點的最大值等於上面和左邊兩個點的值的最大值加上右下角值,而左邊或者上面的最大值亦是如此。因此可以將某個點的狀態定義爲到達該點路徑累加和的最大值。
代碼塊
Java
Scanner sc = new Scanner(System.in);
int raw[][] = {{1,3,3},{2,1,3},{2,2,1}};
int dp[][] = new int[3][3];
int n = 3;
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if(i == 0 && j==0)
dp[i][j] = raw[i][j];
else if(i == 0 && j != 0){
dp[i][j] = dp[i][j-1] + raw[i][j];
}else if(i != 0 && j == 0){
dp[i][j] = dp[i-1][j] + raw[i][j];
}else {
dp[i][j] = Math.max(dp[i][j-1],dp[i-1][j]) + raw[i][j];
}
}
}
System.out.println(dp[n-1][n-1]);
// 測試代碼功能沒有問題,只是代碼可能沒必要有這麼多的分支條件。 TODO優化條件分支
2.3 最長子串
狀態定義:MaxSum[i]就表示A[0...i]以A[i]結尾的子數組最大和,那麼MaxSum[i]就等於A[0...i-1]的最大和加上A[i]在和A[i]比較求最大值
狀態轉移方程:MaxSum[i] = Max{ MaxSum[i-1] + A[i], A[i]}
代碼塊
Java
public static void main(String[] args) {
// 最大子段和 狀態Fi(i<=n)定義爲考慮從零到i的序列其最大字段和爲Fi, 則狀態轉義方程爲 Fi = Fi +
int [] MaxSum = new int[6];
int array [] = {-5,5,5,5,-16,4};
int length = array.length;
MaxSum[0]=array[0];
for(int i=1;i<length;i++){
MaxSum[i]=Math.max(MaxSum[i-1]+array[i], array[i]);
}
for (int i = 0; i < MaxSum.length; i++) {
System.out.println(MaxSum[i]);
}
//找到MaxSum中的最大值
int maxSum=Integer.MIN_VALUE;
for(int i=0;i<MaxSum.length;i++){
if(MaxSum[i]>maxSum){
maxSum=MaxSum[i];
}
}
System.out.println(maxSum);
}
2.4 揹包問題
揹包問題就沒有以上兩個問題,那麼容易找到狀態。
在N件物品取出若干件放在容量爲W的揹包裏,每件物品的體積爲W1,W2……Wn(Wi爲整數),與之相對應的價值爲P1,P2……Pn(Pi爲整數)。求揹包能夠容納的最大價值。
3 dp總結
TODO 場景千千萬萬,但是是否有某種規律,能快速的針對給定場景分析出狀態的定義???
最長非降序列長度的問題,其實都是單序列問題,其i都是等於前面的若干位置的子問題的某種計算
寶石問題和硬幣問題感覺是同一個問題。寶石問題就是雙序列問題,寶石問題有兩個屬性體積和價值兩個序列,在限定體積的情況下,求價值最大值。
硬幣問題相當於體積是定值,在限定價值的情況下,求最小體積?
感覺寶石問題是雙序列,硬幣由於體積固定是但序列問題?