完全背包描述:
总承受重量为m的背包和n种物品,每个物品都有各自的重量Weight和价值Value,每种物品都有无限件可用,将哪些物品装入背包物品重量总数不超过包的总承受重量m 时,能够得到的最大价值是多少?
思路:
对dp[i][j]这个集合进行划分,对i这件物品,可以令k取0,1,2,3,…一直取到超出该背包大小.
那么dp[i][j] = max(dp[ i-1 ] [ j ], dp[ i-1 ] [ j - Weight[ i ]] + Value[i],
dp[ i - 1] [j - 2 * Weight[ i ]] + 2 * Value[i] ,…)
那么k从0开始枚举 一直枚举到超出背包大小就得到dp[n][m];
递推
dp[i][j] =
MAX(dp[i-1][j - k * Weight[i]] + Value[i] * k)
朴素版完全背包
#include <iostream>
using namespace std;
const int N = 1010;
int dp[N][N];//dp[i][j] 代表在前i个物品中 选取总重量不超过j的最大值
int Value[N], Weight[N];//记录 价值和 重量
int n;//n代表物品个数
int BagSize;//m代表背包总大小
//最重要的是对这个集合的划分
//可以将f(i,j) 划分成当前物品 选0 1 2 3 ....直到达到j这个重量
//那么就是 f[i-1][j- Weight[i]*k] + Value[i]*k
int main(int argc, char** argv)
{
cin>>n>>BagSize;
//读取每个物品的 重量 和 价值
for(int i = 1; i <= n; i++)
{
cin>>Weight[i]>>Value[i];
}
//
for(int i = 1; i <= n; i++)
{
for(int j = 0; j <= BagSize; j++)
{
//当前这个物品从0个一直选 直到达到重量 j
for(int k = 0; k * Weight[i] <= j; k++)
{
dp[i][j] =
max(dp[i-1][j- k*Weight[i]] + Value[i]*k,dp[i][j]);
}
}
}
cout<<dp[n][BagSize]<<endl;
return 0;
}
优化版完全背包问题
//以下的weight[i] 和 Value[i]都简化为 W 和 V
//dp[i][j] = max(dp[i-1][j], dp[i-1][j-W]+V, dp[i-1][j-2W]+2V, dp[i-1][j-3W]+3V)
//dp[i][j-W] = max( dp[i-1][j-w], dp[i-1][j-2w]+w, dp[i-1][j-3w]+2*v )
//==> dp[i][j] = max(dp[i-1][j], dp[i][j-Weight[i]]+Value[i])
dp[j] = max(dp[j],dp[j-Weight[i]] + Value[i])
#include <iostream>
using namespace std;
const int N = 1010;
int dp[N];
int Weight[N];//重量
int Value[N];//价值
int BagSize;//背包大小
int n;//n个物品
//以下的weight[i] 和 Value[i]都简化为 W 和 V
//dp[i][j] = max(dp[i-1][j], dp[i-1][j-W]+V, dp[i-1][j-2*W]+2*V, dp[i-1][j-3*W]+3*V)
//dp[i][j-W] = max( dp[i-1][j-w], dp[i-1][j-2*w]+w, dp[i-1][j-3*w]+2*v )
//==> dp[i][j] = max(dp[i-1][j], dp[i][j-Weight[i]]+Value[i])
int main(int argc, char** argv)
{
cin>>n>>BagSize;
for(int i = 1; i <= n; i++)
{
cin>>Weight[i]>>Value[i];
}
for(int i = 1; i <= n; i++)
{
//注意这里与01背包的区别 请独立思考为什么?
for(int j = Weight[i]; j <= BagSize; j++)
{
dp[j] = max(dp[j],dp[j-Weight[i]]+Value[i]);
}
}
cout<<dp[BagSize]<<endl;
return 0;
}