最長不減子序列收集最多的蘋果01背包問題問題描述問題分析代碼實(shí)現(xiàn)
一個(gè)序列有N個(gè)數(shù):A[1],A[2],…,A[N],求出最長非降子序列的長度。 (講DP基本都會(huì)講到的一個(gè)問題LIS:longest increasing subsequence)
正如上面我們講的,面對(duì)這樣一個(gè)問題,我們首先要定義一個(gè)“狀態(tài)”來代表它的子問題, 并且找到它的解。注意,大部分情況下,某個(gè)狀態(tài)只與它前面出現(xiàn)的狀態(tài)有關(guān), 而獨(dú)立于后面的狀態(tài)。
5,3,4,8,6,7
根據(jù)上面找到的狀態(tài),我們可以得到:(下文的最長非降子序列都用LIS表示)
前1個(gè)數(shù)的LIS長度d(1)=1(序列:5)前2個(gè)數(shù)的LIS長度d(2)=1(序列:3;3前面沒有比3小的)前3個(gè)數(shù)的LIS長度d(3)=2(序列:3,4;4前面有個(gè)比它小的3,所以d(3)=d(2)+1)前4個(gè)數(shù)的LIS長度d(4)=3(序列:3,4,8;8前面比它小的有3個(gè)數(shù),所以 d(4)=max{d(1),d(2),d(3)}+1=3)狀態(tài)轉(zhuǎn)換分成為:
d(i) = max{1, d(j)+1},其中j
#include <iostream>using namespace std;int lis(int A[], int n){ int *d = new int[n]; int len = 1; for(int i=0; i<n; ++i){ d[i] = 1; for(int j=0; j<i; ++j) if(A[j]<=A[i] && d[j]+1>d[i]) d[i] = d[j] + 1; if(d[i]>len) len = d[i]; } delete[] d; return len;}int main(){ int A[] = { 5, 3, 4, 8, 6, 7 }; cout<<lis(A, 6)<<endl; return 0;}以上是O(
參考:
http://www.hawstein.com/posts/dp-novice-to-advanced.html https://www.felix021.com/blog/read.php?1587
平面上有N*M個(gè)格子,每個(gè)格子中放著一定數(shù)量的蘋果。你從左上角的格子開始, 每一步只能向下走或是向右走,每次走到一個(gè)格子上就把格子里的蘋果收集起來, 這樣下去,你最多能收集到多少個(gè)蘋果。
解這個(gè)問題與解其它的DP問題幾乎沒有什么兩樣。第一步找到問題的“狀態(tài)”, 第二步找到“狀態(tài)轉(zhuǎn)移方程”,然后基本上問題就解決了。
首先,我們要找到這個(gè)問題中的“狀態(tài)”是什么?我們必須注意到的一點(diǎn)是, 到達(dá)一個(gè)格子的方式最多只有兩種:從左邊來的(除了第一列)和從上邊來的(除了第一行)。 因此為了求出到達(dá)當(dāng)前格子后最多能收集到多少個(gè)蘋果, 我們就要先去考察那些能到達(dá)當(dāng)前這個(gè)格子的格子,到達(dá)它們最多能收集到多少個(gè)蘋果。 (是不是有點(diǎn)繞,但這句話的本質(zhì)其實(shí)是DP的關(guān)鍵:欲求問題的解,先要去求子問題的解)
經(jīng)過上面的分析,很容易可以得出問題的狀態(tài)和狀態(tài)轉(zhuǎn)移方程。 狀態(tài)S[i][j]表示我們走到(i, j)這個(gè)格子時(shí),最多能收集到多少個(gè)蘋果。那么, 狀態(tài)轉(zhuǎn)移方程如下:
其中i代表行,j代表列,下標(biāo)均從0開始;A[i][j]代表格子(i, j)處的蘋果數(shù)量。
S[i][j]有兩種計(jì)算方式:1.對(duì)于每一行,從左向右計(jì)算,然后從上到下逐行處理;2. 對(duì)于每一列,從上到下計(jì)算,然后從左向右逐列處理。 這樣做的目的是為了在計(jì)算S[i][j]時(shí),S[i-1][j]和S[i][j-1]都已經(jīng)計(jì)算出來了。
偽代碼如下:
#include <iostream> using namespace std; #define MAX_N 100 #define MAX_M 100 int arr[ MAX_N ][ MAX_M ] = { 0 }; int dp[ MAX_N + 2 ][ MAX_M + 2 ] = { 0 }; int main(){ int n, m; cin>> n >> m; //輸入n*m的方格 int i, j ; for( i = 0; i < n; i++){ for( j = 0; j < m; j++) cin>> arr[ i ][ j ]; } //輸入方格中各個(gè)格子中的蘋果數(shù)量 for( i = 0; i < n; i++){ for( j = 0; j < m; j++){ dp[ i + 1 ][ j + 1 ] = dp[ i ][ j + 1] > dp[ i + 1 ][ j ] ? dp[ i ][ j + 1] + arr[ i ][ j ] : dp[ i + 1][ j ] + arr[ i ][ j ]; } } cout<<dp[i][j]<<endl; return 0; }http://www.tuicool.com/articles/IVVvue
有編號(hào)分別為a,b,c,d,e的五件物品,它們的重量分別是2,2,6,5,4,它們的價(jià)值分別是6,3,5,4,6,現(xiàn)在給你個(gè)承重為10的背包,如何讓背包里裝入的物品具有最大的價(jià)值總和?
01背包的狀態(tài)轉(zhuǎn)換方程 f[i,j] = Max{ f[i-1,j-Wi]+Pi( j >= Wi ), f[i-1,j] }
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注