有n个重量和价值分别为wi,vi的物品,从这些物品中挑选出总重量不超过W的物品,求所有挑选方案中价值总和的最大值
1≤n≤100
1≤wi,vi≤100
1≤W≤10000
其实这个问题01背包问题的区别在与,这里的每个物品都是可以重复取的。而01背包问题就只能取一次;
在原01背包问题中:
递推式为: dp [ i ] [ j ] = max( dp[ i-1 ] [ j - weight [ i ] ] + value [ i ] , dp[ i-1 ] [ j ] )
式子的含义为 : 当我背包的容量为 J 时,我是否取第 i 个物品
(1)如果取: **dp[ i-1 ] [ j - weight [ i ] ] + value [ i ]** :
背包要放入物品 **i** , 那么背包必须有容纳得下 **i** 物品的空间 ,
所以前一状态背包用量有 :**[ j - weight [ i ] ]** ,
既然我的物品只能取一次,所以 **[ i - 1 ]** (过度回取第 i- 1 号物品 的情况,保证i 号物品 只被取一次), 才有此式子。
(2) 如果不取,那么就是直接返回前状态 : dp[ i-1 ] [ j ]
那么ok, 我们现在想一想,如果我可以反复取 i 号物品(在容量J 允许的情况下) ,
那么如果我取了 i 号物品 一次后, 我就不需要过度回 取 i- 1 号物品的 状态了 。
因为假设取了一次之后,背包容量还可以再一次纳入此物品,那么 只需要在我取了第一次的基础上,在加一次就ok 啦。而第一次取得记录已经被记录入 dp [ i ] [ j - weight [ i ] ] + value[ i ] (为什么不是 i-1 ??? -----已经说了:可以多次取,不需要过度回 i-1 的状态来保证只取一次)了。
所以 最 终 结 论 完全背包问题 的 递 推 式 :
dp[ i ] [ j - weight [ i ] ] + value [ i ] , dp[ i-1 ] [ j ]
物品 | 价值 | 重量 |
---|---|---|
物品1 | 4 | 3 |
物品2 | 5 | 4 |
物品3 | 3 | 2 |
容量vol = 7;
(直接跳到允许放入的时候)
1) dp [ 1 ] [ 3 ] = max( dp[ i ] [ 3-3 ] + value [ 1 ] , dp [ 0 ] [ 3 ] )
==> dp [1] [3] = max ( 0 + 4 , 0)
2)dp [ 1 ] [ 4 ] = max( dp[ 1 ] [ 4-3 ] + value [ 1 ] , dp [ 0 ] [ 4 ] )
==> dp [1]\ [4] = max ( 0 + 4 , 0)
3)dp [ 1 ] [ 5 ] = max( dp[ 1 ] [ 5-3 ] + value [ 1 ] , dp [ 0 ] [ 5 ] )
==> dp [1] [5] = max ( 0 + 4 , 0)
!!!重点来了
4)dp [ 1 ] [ 6 ] = max( dp[ 1 ] [ 6-3 ] + value [ 1 ] , dp [ 0 ] [ 6 ] )
dp [ 1 ] [ 6 ] = max( dp[ 1 ] [ 3 ] + value [ 1 ] , dp [ 0 ] [ 6 ] )
==> dp [1] [6] = max ( 4 + 4 , 0)
!!是不是在原来已经放了物品1的基础上又放了物品!!
如果是01背包问题就是:
dp [ 1 ] [ 6 ] = max( dp[ 1-1 ] [ 6-3 ] + value [ 1 ] , dp [ 0 ] [ 6 ] )
dp [ 1 ] [ 6 ] = max( dp[ 0 ] [ 3 ] + value [ 1 ] , dp [ 0 ] [ 6 ] )
==> dp [1] [6] = max(0 + 4 , 0)
#include
using namespace std;
int main()
{
int n;
int vol ;
cin>>n;
int value[n]={0};
int weight[n]={0};
int dp[10][10] ={0};
for(int i=1;i<=n;i++)
{
cin>>value[i];
}
for(int j=1;j<=n;j++)
{
cin>>weight[j];
}
cin>>vol;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=vol;j++)
{
if(weight[i]<=j)
{
dp[i][j] = max(dp[i][j - weight[i]] + value[i], dp[i-1][j]);
}
else
{
dp[i][j] = dp[i-1][j];
}
}
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=vol;j++)
{
cout<
友情提示:
关于01背包问题,推荐一位博主:
[简书] 01背包问题
~第一次写博,可能很罗嗦,也可能有错误,欢迎指点,谢谢亲故
~
你可能感兴趣的:(dynamic,programming)