为了账号安全,请及时绑定邮箱和手机立即绑定

背包——01背包Bone Collector(hdu2602)

标签:
算法

首先说明一下01背包


有一个容量为V的背包,另外有N个物品,每个物品Ni都有其对应的体积Vi和价值Pi

求如何取舍装进背包中使得背包里的总价值P达到最大值


题目看似很像贪心问题,把我们不妨先以贪心的思路解决一下这个问题


每个物品都有其对应的价值与体积,我们将其做比,优先选择其比值较高的物品

设:总容量为100,物品N为3

物品A:容量50 价值9K

物品B:容量40 价值7K

物品C:容量55 价值11K

 则贪心的选择顺序为->C->B此时A无法装入,舍弃。 虽然只用了95的总容量,但是其价值确实是最大化,看起来似乎没什么不对。

那么我们再看一组数据


物品A:容量50 价值9K

物品B:容量40 价值11K

物品C:容量65 价值19K

假如我们仍以贪心的思路去选择,我们就会发现,即使C的“性价比”很高,但是我们如果选择了他,就无法再装入其他物品,浪费了容量空间,

还不如选择A+B的价值更大。所以,贪心思想解决不了背包的问题。


问题出在哪里了呢? 对于每一个物品我们都有装和不装两种选择,对于计算机而言,就像是0和1两种状态一样,所以这类问题我们称之为01背包

我们纠结的地方就在于我们单独去看一个物品(亦或几个物品)的时候我们并不知道他到底选还是不选,我们也无法保证当看过n个物品后,我将以

多少剩余容量去面对接下来未知的物品。

所以,我们必须要把看过n个物品之后,所有容量的情况全部考虑进去。



即:外层循环从1到N,用于遍历N个物品,内层循环从0(我们暂且认为没有容量小于0的物品)到V  

即浏览到Ni时,任意一个容量值j的最优价值都计算出来

计算的公式为:当前容量值j如果大于Vi,那么有两种选择——选该物品i,那么当前容量j的价值就变成了j-Vi的最优价值+i的价值,或者是不选择该物品,保留j的价值

即  f(i,j)=max{f(i-1,Pj),f(i-1,P[j-v[i]]+Pi

可能有一些绕,举个例子说明:还是上面的数据,假设我们考虑到C:

那么 对于我每一个容量点(0~100)都要进行是否去物品C的判断,比如说容量50,很明显,装不下,比如说容量90,我要看在我不选物品C之前,我容量80时最大的

价值是多少,如果我选择这个物品C,那么我的价值就是 容量为:90-65=25时我能获取的价值 再加上物品C本身的价值。

不加C时容量90的价值为A+B=20k ,加C为容量25(没有合适的物品,价值为0)+C的价值=0+19=19k,很显然,选择C是一种不合适的行为。


也就是我们的代码为:

for(i=1;i<=n;i++)    //外层循环物品个数
    {
        for(j=0;j<=v;j++) //内层循环每个容量点
        {
            if(j-b[i]>=0)
            dp[i][j]=fmax(dp[i-1][j],dp[i-1][j-b[i]]+a[i]);    //容量大于该物品体积时状态转移方程
            else 
    dp[i][j]=dp[i-1][j];          //容量小于该物品体积,只能舍弃

        }
  }


想必到此大家应该明白01背包的解决思路了,下面为hdu一道01背包题



题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=2602


题目描述:和01背包基本意思一样, 收集骨头


#include<stdio.h>	int dp[1020][1020];int fmax(int a,int b){	return a>b?a:b;}int main(){	int b[1020];	int a[1020];	int t,n,i,j,v;		scanf("%d",&t);	while(t--)	{	scanf("%d%d",&n,&v);for(i=1;i<=n;i++)	scanf("%d",&a[i]);	for(i=1;i<=n;i++)	scanf("%d",&b[i]);		for(i=1;i<=n;i++){for(j=0;j<=v;j++){if(j-b[i]>=0)dp[i][j]=fmax(dp[i-1][j],dp[i-1][j-b[i]]+a[i]);else 			dp[i][j]=dp[i-1][j];}}printf("%d\n",dp[n][v]);}return 0;}


点击查看更多内容
1人点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消