题目
题目:一个叫Eric(秦贼)的小偷去商店里偷东西,Eric的袋子体积为m,商店里有n种物品,价值为c[i],体积为v[i]。由于Eric开了外挂,导致每样商品都有无数件可以取,求背包中最多能放的物品的价值是最大多少?
输入:
第一行两个整数n,m
第2~n-1行,每行输入v[i],c[i]
输出:
前面说过
样例输入:
4 10
2 1
3 3
4 5
7 9
样例输出:
12
思路(二维做法)
完全背包和01背包的区别就在于:完全背包中每样物品都有无限件,而01背包只有1件,不仅仅是01背包的“取”或者“不取”。
我们先来想想二维数组的解法
首先,我们可以确定代码需要二重循环,即第一重1~n,第二重1~m。
1~n的含义很清楚,n件商品遍历一遍,1~m的含义也不难得出是遍历每种商品下的容积。
注意:!dp[i][j]代表前i件物品,总重量不超过j的最后价值!
循环确定好了,现在来看看循环内些什么。
01背包写法:dp[i][j]=max(dp[i-1][j],dp[i-1][j-1])+a[i][j];
前面说过,完全背包和01背包的差别就在于物品的数量。
这里也会有两种情况,即背包对物品是“容积足够,能放进”还是“容积不够,不能放进”
如果是“容积不够,不能放进”,那么自然不能取,即第1-(i-1)件的物品的总质量等于1-(i-1)件物品的价值。
如果是“容积足够,能放进”,那么就需要比较这件物品放不放,此时“这件物品”已经变成了1个,
那么就可以用01背包公式,也就是dp[i][j]=max(dp[i-1][j],dp[i-1][j-1])+a[i][j]做了
代码
#include <cstdio>
#include <algorithm>
using namespace std;
int main()
{
int n,m,c[101],v[101],dp[101][101];
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d%d",&v[i],&c[i]);
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(j<v[i])//容积不够,不能放进
{
dp[i][j]=dp[i-1][j];
}
else//容积足够,能放进
{
dp[i][j]=max(dp[i-1][j],dp[i][j-v[i]]+c[i]);
}
}
}
printf("%d",dp[n][m]);//最大值存在dp[n][m]
}
一维做法
一维做法本质上和01二维变为01一维没有区别
代码上直接看注释吧
#include <cstdio>
#include <algorithm>
using namespace std;
int main()
{
int n,m,c[101],v[101],dp[101]={0};
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d%d",&v[i],&c[i]);
}
for(int i=1;i<=n;i++)
{
for(int j=v[i];j<=m;j++)//设dp[j]表示体积不超过V的最大价值
{
dp[j]=max(dp[j],dp[j-v[i]]+c[i]);//“取”or“不取”
}
}
printf("%d",dp[m]);//存在dp[m]里
}
总结!
01背包和完全背包几乎没有区别,个别的区别上面已经提到过了。
其实完全背包只需要在循环中把完全背包拆分成几个小的01背包做,
问题也就变成简单的01背包了