完全背包详讲

题目

题目:一个叫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背包了

END

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值