DP經典例題 揹包專題

2021-09-11 17:49:02 字數 4417 閱讀 6613

揹包的基本模型:

給你乙個容量為v的揹包和若干種物品,在一定的限制條件下(每種物品都占用一定容量),問最多能放進多少價值的物品?

題意:有n個重量和價值分別為wi,vi,從這些物品中挑選總重量不超過w的物品,使其價值最大,輸出價值最大值(其中每個物品最多只能放一件);

這題其實用dfs也可以做,但超時

①、確認子問題和狀態

01揹包問題需要求解的就是,為了重量為w的揹包中物體總價值最大化,n件物品中第i件應該放入揹包中嗎?(其中每個物品最多只能放一件);

為此,我們定義乙個二維陣列,其中每個元素代表乙個狀態,即前i個物體中若干個放入重量為w揹包中最大價值。陣列為:dp[n][v],其中dp[i][j]表示前i件中若干個物品放入體積為j的揹包中的最大價值

②、初始狀態

dp[i][j] = 0;

轉移方程:dp[i][j] = max(dp[i-1][j],dp[i-1][j-w[i]]+v[i]);也就是兩種狀態,第i個物品放還是不放(也就是前i件中是否加入第i件產品進入體積為j的揹包),放則為:dp[i-1][j-w[i]]+v[i]

不放則為:dp[i-1][j]

#includeusing namespace std;

const int maxn = 1000+10;

int dp[maxn][maxn] = ;

int w[maxn];

int v[maxn];

/*因為我需要從上層推下層,如果dp陣列下標從0開始會比較麻煩點,所以這裡我從1開始

*/int main()

for(int i = 1;i <= n;++i)

else

dp[i][j] = dp[i-1][j];}}

/*這裡我覺得會給大家乙個錯覺,認為dp[n][v]就是最大,其實我們應該遍歷dp[n][i]得到最大

再輸出。這裡為何會直接輸出dp[n][v],試想dp[i][j]與dp[i][j-1]相比,如果j-1可以放入第i件

,那麼j必定可以,所以這裡其實已經保持最大了,所以只需要輸出dp[n][v]

當w = 12,n = 5,

v[6] = ;    //價值

w[6]   = ;     //重量

此題空間可以優化:大家看看這張表,再看看轉移方程:dp[i][j] = max(dp[i-1][j],dp[i-1][j-w[i]]+v[i]);我們可以用滾動陣列,因為前i件只取決前i-1件的狀態(不取決i-2,i-3之類的),也就無需儲存所有的狀態,只需儲存當前狀態的上一層狀態,這裡注意此時w需要從大到小來遍歷,為什麼呢?請看

優化後的轉移方程:dp[j] = max(dp[j],dp[j-w[i]]+v[i]);

未優化後的轉移方程:dp[i][j] = max(dp[i-1][j],dp[i-1][j-w[i]]+v[i]);

當w從小到大來,dp[j-w[i]]取到的已不是前i-1的狀態而是前i的狀態,你可以想想,j從小到大變化是不是把dp[j]給修改,而這裡修改是在前i的狀態下,當dp[j] = max(dp[j],dp[j-w[i]]+v[i])中dp[j-w[i]]取到的j是已被修改的,相當於二維中的dp[i][j-w[i]]而不是dp[i-1][j-w[i]]

#include#include#include#include#include#include#includeusing namespace std;

int dp[1005];

int main()

} printf("%d\n",dp[w]);

return 0;

}

n件物品,容量位w的揹包。第i件物品的重量為wi,價值為vi,每件物品有無數個,求裝的最大價值

同樣,定義乙個二維陣列dp[i][j],表示取前i件中的若干件,在容量為j的揹包中的最大價值

dp[i][j] = max(dp[i][j],dp[i-1][j-k*w[i]]);  (0<=k<=w/wi),這裡k是從0開始

顯然時間複雜度比較大,所以需要優化,推導如下:

1.dp[i][j] = max(dp[i-1][j-k*w[i]]);    k>=0

2.dp[i][j] = max(dp[i-1][j],dp[i-1][j-k*w[i]]);  k>=1

3.dp[i][j] = max(dp[i-1][j],dp[i-1][j-w[i]-k*w[i]]);  k>=0

將1和3

1.dp[i][j] = max(dp[i-1][j-k*w[i]]);    k>=0

3.dp[i][j] = max(dp[i-1][j],dp[i-1][j-w[i]-k*w[i]]);  k>=0

dp[i-1][j-w[i]-k*w[i]]和dp[i-1][j-k*w[i]]等價,所以把j-w[i]當成j,所以1.dp[i][j] = max(dp[i-1][j-k*w[i]])就變成dp[i][j-w[i]] = max(dp[i-1][j-k*w[i]]),而dp[i-1][j-k*w[i]]可以代替2中的dp[i-1][j-k*w[i]],2轉化為dp[i][j] = max(dp[i-1][j],dp[i][j-w[i]])

可能大家被上面的轉換轉暈了,沒事大家可以看我在時間優化裡寫的注釋,相信大家絕對看的懂。

此時還可以優化空間,也是用滾動陣列了,只不過此時j不必4從大到小了,因為max(dp[i-1][j],dp[i][j-w[i]]),這裡是前i種狀態

#include #include #include #include using namespace std;

const int maxn = 1000+10;

int dp[maxn][maxn]=;

int main()}}

printf("%d\n",dp[n][w]);

return 0;

}

#include #include #include #include using namespace std;

int main()

; int w[105];

int v[105];

int w;

int n;

scanf("%d",&n);

for(int i = 1;i <= n;++i)

scanf("%d%d",&w[i],&v[i]);

scanf("%d",&w);

/*f[i,j]=max(f[i-1][j],f[i-1][j-w]+v,f[i-1][j-2w]+2v,f[i-1][j-3w]+3v,......)

f[i,j-v] = max( f[i-1][j-w], f[i-1][j-2w]+v ,f[i-1][j-3w]+2v,......)

可以發現f[i-1][j-w]+v,f[i-1][j-2w]+2v,f[i-1][j-3w]+3v,......這一堆等價於f[i,j-w]+v

所以f[i,j]=max(f[i-1][j],f[i,j-w]+v);所以我們可以把k去掉

*/ for(int i = 1;i <= n;++i)

}printf("%d\n",dp[w]);

return 0;

}

#include #include #include #include using namespace std;

int main()

; int w[105];

int v[105];

int w;

int n;

scanf("%d",&n);

for(int i = 1;i <= n;++i)

scanf("%d%d",&w[i],&v[i]);

scanf("%d",&w);

for(int i = 1;i <= n;++i)

}printf("%d\n",dp[w]);

return 0;

}

DP 分組揹包例題

例9.16 分組揹包 時間限制 1000 ms 記憶體限制 65536 kb 提交數 192 通過數 122 題目描述 乙個旅行者有乙個最多能裝 v公斤的揹包,現在有 n件物品,它們的重量分別是w1 w2,wn w1,w2,wn 它們的價值分別為c1 c2,cn c1,c2,cn 這些物品被劃分為若...

DP 揹包專題 揹包九講

這段時間看了 揹包九講 在hust vjudge上找到了乙個題單,挑選了其中16道題集中做了下,選題全部是hdu上的題,大多是簡單題。目前做了點小總結,大概提了下每道題的思路重點部分,希望以後回看回想時能有幫助。題單 hdu 1059 hdu 1114 hdu 1171 hdu 1203 hdu 1...

dp專題 簡單基礎dp 揹包

按照這個做的 hdu 1864 最大報銷額 01揹包 方法一 double型別的揹包 總數30個 每個最大1000 保留2位有效位。直接把double 100轉換為int型的揹包 看清題目 double型的01揹包 include include include using namespace st...