什麼是動態規劃(dp)?
1)動態規劃是運籌學中用於求解決策過程中的最優化數學方法。當然,我們在這裡關注的是作為一種演算法設計技術,作為一種多階段決策過程最優的通用方法。
他是應用數學中用於解決某類最優化問題的重要工具。
2)如果問題是由交疊的子問題所構成,我們就可以用動態規劃技術來解決它,一般來說,這樣的子問題出現在對給定問題求解的遞推關係中,這個遞推關係包含了相同問題的更小子問題的解。動態規劃法建議,與其對交疊子問題一次又一次的求解,不如把每個較小子問題只求解一次並把結果記錄在表中(動態規劃也是空間換時間的),這樣就可以從表中得到原始問題的解。
它往往是解決最優化問題的:不論初始狀態和第一步決策是什麼,餘下的決策相對於前一次決策所產生的新狀態,構成乙個最優決策序列。
最優決策序列的子串行,一定是區域性最優決策子串行。包含有非區域性最優的決策子串行,一定不是最優決策序列。
問題可以表現為多階段決策:如果一類問題的求解過程可以分為若干個互相聯絡的階段,在每乙個階段都需作出決策,並影響到下乙個階段的決策。
多階段決策問題,就是要在可以選擇的那些策略中間,選取乙個最優策略,使在預定的標準下達到最好的效果.
交疊子問題:什麼是交疊子問題,最優子結構性質。
動態規劃的思想是什麼:記憶,空間換時間,不重複求解,由交疊子問題從較小問題解逐步決策,構造較大問題的解。
動態規劃的指導思想:
在做每一步決策時,列出各種可能的區域性解
依據某種判定條件,捨棄那些肯定不能得到最優解的區域性解。
以每一步都是最優的來保證全域性是最優的。
下面通過例題來詳細的介紹一下動態規劃的思想。
例題:複製書稿
假設有m本書(編號為1,2,…m),想將每本複製乙份,m本書的頁數可能不同(分別是p1,p2,…pm)。
任務:將這m本書分給k個抄寫員(k<=m) 每本書只能分配給乙個抄寫員進行抄寫,而每個抄寫員所分配到的書必須是連續順序的。
複製工作是同時開始進行的,並且每個抄寫員複製一頁書的速度都是一樣的。所以,複製完所有書稿所需時間取決於分配得到最多工作的那個抄寫員的複製時間。
試找乙個最優分配方案,使分配給每乙個抄寫員的頁數的最大值盡可能小。
設dp[i][j]表示前i本書由j個人複製所需要的最少時間,有狀態轉移方程
dp[i][j]=min(dp[i][j],max(dp[v][j-1],sum[v+1][i]))
其中1<=i<=m,1<=j<=k,j-1<=v<=i-1,sum[v+1][j]表示第v+1本書到第i本書的頁數之和
const int maxn = 510;
int sum[maxn],path[maxn],dp[maxn][maxn];
int main()
else
}dp[low]=data[i];
if( low>len )
}return len;
}例題:最長公共子串行(lcs)
給出兩個字串a, b,求它們的最長、連續的公共字串。
這很容易就想到以dp[i][j]表示a串匹配到i,b串匹配到j時的最大長度。則:
0 i==0 || j==0
dp[i][j]=dp[i-1][j-1]+ 1 a[i]==b[j]
max(dp[i-1][j],dp[i][j-1]) 不是以上情況
但這樣實現起來的空間複雜度為o(n^2),而上面的方程只與第i-1行有關,所以可以用兩個一維陣列來代替。以下是**:
//最長公共子串行
const int size=1001;
int dp[2][size]; //兩個一維陣列
//輸入兩個字串,返回最大的長度
int lcs(const string& a,const string& b)
flag=1-flag;
}return dp[1-flag][b.size()];
}例題:01揹包
有n件物品和乙個容量為v的揹包。第i件物品的大小是c[i],價值是w[i]。求解將哪些物品裝入揹包可使價值總和最大。
用dp[i][j] 表示前i件物品放入乙個容量為j的揹包可以獲得的最大價值。則
dp[i][j]= dp[i-1][j] ,j=c[i]
這樣實現的空間複雜度為o(vn),實際上可以優化到o(v)。以下是**:
const int maxw=13000; //最大重量
const int maxn=3450; //最大物品數量
int c[maxn]; //物品的存放要從下標1開始
int w[maxn]; //物品的存放要從下標1開始
int dp[maxw];
//不需要將揹包裝滿,則將dp陣列全部初始化為0
//要將揹包裝滿,則初始化為dp[0]=0,dp[1]…dp[v]=-1(即非法狀態)
int packet(int n,int v)
}return dp[v];
}例題:完全揹包問題
有n種物品和乙個容量為v的揹包,每種物品都有無限件可用。第i種物品的費用是c[i],價值是w[i]。求解將哪些物品裝入揹包可使這些物品的費用總和不超過揹包容量,且價值總和最大。
很容易可以得到這種狀態表示:用dp[i][j] 表示前i件物品放入乙個容量為j的揹包可以獲得的最大價值。則
dp[i][j]=max(dp[i-1][j],dp[i-1][j-k*c[i]]+k*w[i]) 0<=k*c[i]<=j
這樣的複雜度是o(v*σ(v/c[i]))
有更好的做法,那就是利用01揹包的優化原理。在優化的**中,之所以第二重迴圈是倒序,是為了防止重複拿,那麼只要將其變為順序即可以重複取。**就不給了。
多重揹包問題
有n種物品和乙個容量為v的揹包。第i種物品最多有n[i]件可用,每件費用是c[i],價值是w[i]。求解將哪些物品裝入揹包可使這些物品的費用總和不超過揹包容量,且價值總和最大。
這題仍然可以用到上一題的思想,dp表示狀態與上面的相同。方程為:
dp[i][j]=max(dp[i-1][j],dp[i-1][j-k*c[i]]+k*w[i])
不同的是k的範圍,0<=k<=n[i] && 0<=k*c[i]<=j
這樣的複雜度為o(v*σn[i])。
有更好的想法就是先用二進位制來劃分。將第i種物品分成若干件物品,其中每件物品有乙個係數,這件物品的費用和價值均是原來的費用和價值乘以這個係數。使這些係數分別為1,2,4,...,2^(k-1),n[i]-2^k+1,且k是滿足n[i]-2^k+1>0的最大整數。然後用01揹包做,這樣的複雜度為o(v*σlog n[i])。關鍵**:
const int size=1001;
int dp[size];
int num[size],c[size],w[size]; //num[i]是i物品的件數,c[i]是費用,w[i]是價值
int multipack(int n,int v)
}else
num[i]-=k;
k*=2;
}for(j=v;j>=num[i]*c[i];--j) }}
return dp[v];
動態規劃總結
華電北風吹 天津大學認知計算與應用重點實驗室 日期 2015 12 7 近期學了幾個動態規劃正好總結一下。裡面不涉及具體問題的具體解法,有問題可以參看我的具體型別的講解部落格。目前所見動態規劃可以劃分為兩類 鏈式和樹形。而且這兩類中的每個節點都是乙個完整的狀態集合。一 鏈式動態規劃 鏈式動態規劃的題...
動態規劃 總結
動態規劃是解決多階段決策問題的一種方法。如果一類問題的求解過程可以分為若干個互相聯絡的階段,在每乙個階段都需作出決策,並影響到下乙個階段的決策,從而確定了乙個過程的活動路線,則稱它為多階段決策問題。思想 在做每一步決策時,列出各種可能的區域性,解依據某種判定條件,捨棄那些肯定不能得到最優解的區域性解...
動態規劃總結
一 知識點整理 一 動態規劃是解決多階段策略問題的一種方法,運用最優性原理,排除重複計算,用空間換時間的演算法。二 動態規劃適用的題目型別有以下幾個特點 1.問題具有多階段的決策 2.每個階段對應乙個狀態 狀態變數 3.每個階段有乙個決策 不同的決策導致下乙個階段不同的狀態 4.每個階段的最優解可以...