01背包问题动态规划(二维数组)
问题描述
一个旅行者有一个最多能装 M 公斤的背包,现在有 n 件物品,它们的重量分别是W1,W2,…,Wn,它们的价值分别为C1,C2,…,Cn,求旅行者能获得最大总价值。
输入格式
第一行:两个整数,M(背包容量,M<=200)和N(物品数量,N<=30);
第2…N+1行:每行二个整数Wi,Ci,表示每个物品的重量和价值。
10 4
2 1
3 3
4 5
7 9
输出格式
仅一行,一个数,表示最大总价值。
12
代码
#include <iostream>
#include <algorithm>
#include <stdlib.h>
#include <string.h>
int main()
{
int M, N; // M(背包容量,M<=200)和N(物品数量,N<=30);
std::cin >> M >> N;
int dp[N + 1][M + 1];
// dp数组初始化全部 0;
for (int i = 0; i < N + 1; i++)
for (int j = 0; j < M + 1; j++)
dp[i][j] = 0;
int Wi[N + 1] = {0};
int Ci[N + 1] = {0};
memset(Wi, 0, sizeof(Wi));
memset(Ci, 0, sizeof(Ci));
for (int i = 1; i < N + 1; i++)
{
std::cin >> Wi[i] >> Ci[i];
}
/* for (int i = 0; i < N + 1; i++)
{
std::cout << Wi[i] << Ci[i] << std::endl;
} */
for(int i=1; i<N+1; i++)
{
for(int j=1; j<M+1; j++)
{
if(j >= Wi[i]) // 如果可以装下
{
dp[i][j] = std::max(dp[i-1][j], dp[i-1][j-Wi[i]]+Ci[i]);
}
else // 装不下
{
dp[i][j] = dp[i-1][j];
}
}
}
for(int i=0; i<N+1; i++)
{
for(int j=0; j<M+1; j++)
{
std::cout << dp[i][j] << " ";
}
std::cout << std::endl;
}
std::cout << dp[N][M] ;
return 0;
}
总结
1.构造二维dp数组 dp[N+1][M+1]
,N是物品编号,M是背包重量。
2.边界dp[0][M+1]
dp[N+1][0]
全部初始化为0
;
3.背包重量优先遍历(先从左到右,然后上到下)
for(int i=1; i<N+1; i++)
{
for(int j=1; j<M+1; j++)
{
if(j >= Wi[i]) // 如果可以装下
{
dp[i][j] = std::max(dp[i-1][j], dp[i-1][j-Wi[i]]+Ci[i]);
}
else // 装不下
{
dp[i][j] = dp[i-1][j];
}
}
}
4.遍历有两种情况
if(j >= Wi[i]) // 如果可以装下
{
dp[i][j] = std::max(dp[i-1][j], dp[i-1][j-Wi[i]]+Ci[i]);
}
else // 装不下
{
dp[i][j] = dp[i-1][j];
}
如果装不下当前物品:
那么前n个物品的最佳组合和前n-1个物品的最佳组合是一样的。
dp[i][j] = dp[i-1][j];
如果装得下当前物品:
假设1:装当前物品,在给当前物品预留了相应空间的情况下,前n-1个物品的最佳组合加上当前物品的价值就是总价值。
假设2:不装当前物品,那么前n个物品的最佳组合和前n-1个物品的最佳组合是一样的。
选取假设1和假设2中较大的价值,为当前最佳组合的价值。
dp[i][j] = std::max(dp[i-1][j], dp[i-1][j-Wi[i]]+Ci[i]);