问题描述:
给定 n 种物品和一个容量为 w 的背包,物品 i 的价值是 vai,其体积为 voi。
问:应该如何选择装入背包的物品,使得装入背包中的物品的总价值最大?
解题思路:
状态转移方程为:
dp[i][j] = dp[i-1][j] j < vo[i] (即此时的背包容积小于第i个物品的体积)
dp[i][j] = max( dp[i-1][j] , dp[i-1][j-vo[i]] + va[i] ) j >= vo[i] (当背包容积大于第 i 个物品的体积时,有两种选择,选较大的一个)
两种选择:
1、不装这个物品 。则此时dp数组的值还是第i-1个物品是的值,即dp[i-1][j]
2、装下这个物品,此时是dp[i-1][j-vo[i]] + va[i],然后与不装比较看哪种情况装的物品的价值更大
代码:
#include<stdio.h>
#include<algorithm>
using namespace std;
int dp[105][105];
int va[105] , vo[105];//每件物品的价值va和体积vo
int main()
{
int w , n ;//背包的总容量,物品的件数
scanf("%d %d",&n,&w);
for(int i = 1 ; i <= n ; i++)
{
scanf("%d %d",&va[i],&vo[i]);
}
for(int i = 1 ; i <= n ; i++)
{
for(int j = 0 ; j <= w ; j++)
{
if( vo[i] > j)
{
dp[i][j] = dp[i-1][j];
}
else
{
dp[i][j] = max(dp[i-1][j] , dp[i-1][j-vo[i]] + va[i]);
}
}
}
printf("%d\n",dp[n][w]);
return 0;
}
空间优化代码:
只开辟一维dp数组,每次更新是重最后向前循环,毕竟只需要最后一个结果,中间的过程可以不保存,但一定确保从后向前循环
#include<stdio.h>
#include<algorithm>
using namespace std;
int va[105] , vo[105];//每个物品的价值和体积
int dp[105];
int main()
{
int n , w;//物品数量和背包容积
scanf("%d %d",&n,&w);
for(int i = 1 ; i <= n ; i++)
{
scanf("%d %d",&va[i] , &vo[i]);
}
for(int i = 1 ; i <= n ; i++)
{
for(int j = w ; j >= vo[i] ; j--)//要倒着进行,确保在没有被更新的状态下使用
{
dp[j] = max(dp[j - vo[i]] + va[i] , dp[j]);
}
}
printf("%d",dp[w]);
return 0;
}