01背包装满问题(dp)

最好先看完这个

先看满与不满的代码区别,

不装满只求最大价值:将第0行全部初始化为0就完事

装满且价值尽可能大:将第0行第一个元素初始化为0,这一行的其他元素赋值为-∞(-999也行,主要保证其绝对值大于全部物品的价值之和即可) f[0]=0; f[1~n]= -∞

思路
为什么:

对于装满,在没有物品装入的时候,只有容量为0才能装满背包,而容量为正数的时候不可能装满(没有物品塞进去怎么装都不会满)。

因此这里f[1~n]初始化 为-∞相当于标记不能装满。

然后推导第1行,

显然你唯一能填入的正数是刚好塞进第1个物件,因为这条式子dp[j]=max(dp[j],dp[j-weigh[i]]+value[i]);第0行只有1个0,其他都是很负的负数,只有刚好装进第1个物件才有j-weigh[i]等于0,此时dp[j-weigh[i]]才等于0,这个dp[j-weigh[i]]+value[i]才可能为正数,。一旦j-weigh[i]大于0就意味着没塞满,dp[j-weigh[i]]必然为负数,无论如何dp[j-weigh[i]]+value[i]都是负数,这里相当于又标记了一次(没塞满)

到了第2行,

若容量足以再容纳第2件物件,只有当dp[j-weigh[i]]+value[i]为非负数才意味着刚好塞满,因为同上,只有dp[j-weigh[i]]为非负数,dp[j-weigh[i]]+value[i]才可能为非负数,显然j-weigh[i]等于第1件物件重量时dp[j-weigh[i]]为非负数,以此类推

/*问题描述:有编号分别为a,b,c,d,e的五件物品,
它们的重量分别是2,2,6,5,4,它们的价值分别是6,3,5,4,6,
每件物品数量只有一个,
现在给你个承重为10的背包,
如何让背包塞满且里装入的物品具有最大的价值总和?答案是15*/


/*
v w
            输入
6 2
3 2
5 6
4 5
6 4

           */

#include<stdio.h>
int max(int a,int b)
{
    if(a>b)
    {
        return a;
    }
    else
    {
        return b;
    }
}
int main()
{


		int value[30],weigh[30],dp[80],maxn=0;
		int i,j;


for(i=1;i<=5;i++)
{

        scanf("%d %d",&value[i],&weigh[i]);

}
weigh[0]=0;
for(i=0;i<=5;i++)//i负责滚动行的次数,j负责容量变化
{



    for(j=10;j>=weigh[i];j--)
   {


        if(j==0)
        {
            dp[j]=0;//初始化
        }
        if(j!=0&&i==0)
        {
            dp[j]=-999;//初始化
        }
        if(j!=0&&i!=0)
        {
            dp[j]=max(dp[j],dp[j-weigh[i]]+value[i]);
        }


        if(dp[j]>maxn)
        {
           maxn=dp[j];
        }


   }


}

printf("%d",maxn);

	return 0;
}


突然发现,背包最大承重时不一定有最大值。。。
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值