背包问题解题思路

背包解题思路
背包问题大部分都是类似模样的状态转移方程dp[j]=dp[j]>(dp[j-t]+v)?dp[j]:(dp[j-t]+v);
普通类型的背包问题只需注意以下情况:
一、对于物品数量:
1、	01背包:每件物品只有一件:
这表示物品不可以重复取,于是我们里面的循环可以写成for(j=v;j>=c;j--)这样从最大背包重量到只能装下一个当前物品的最小重量,由于是从后向前推的,设v表示背包的体积,c表示物体的体积而前面并没有装任何当前物品,所以就可以做到每个物品至多装下一件。(外层循环是物品件数)
2、	多重背包:
每个物品有有限件(可能是1件或多件,可以多选但不能超过最大件数)
解这类题有两种方法,可行的一种方法是直接把每个物品的N件看成完全相同的N种物品,完成这个操作只需要在外层循环和内层循环之间加上一层while循环即可,就像这样:while(c--)//c即为当前物品的数量
{  
for(j=n;j>=p;j--)/*由于物品被当成多种来对待,所以“每件”不能重复选择*/
{  
dp[j]=max(dp[j],dp[j-p]+h); //状态转移方程,max()为取最大值函数
}  
}

3、	完全背包:每个物品有无限件
这表示每件物品都可以随便取,直到背包装不下为止,于是和单纯的只去一件相对,我们里面的循环可以写成for(j=c;j<=v;j++)这样,从只能装下一个当前物品的最小重量到最大背包重量,由于前面较小的背包重量可能已经装过当前物品了,所以后面的就可以装下重复的物品。
4、	分组背包:物品分为不同的组,每组最多可以取一件(有的题是每组最少取一件)
这种题的解题技巧也是加一层循环,不过不像多重背包,多加的这一层循环作用为在某一组中找出最优解,在这不好说,会在下面题中说明。

二、对于是否需要装满的要求:
技巧就是不需要装满的情况就把数组初始化为0,需要装满就把数组初始化为负无穷。
我们看到的求最优解的背包问题题目中,事实上有两种不太相同的问法。有的题目要求“恰好装满背包”时的最优解,有的题目则并没有要求必须把背包装满。一种区别这两种问法的实现问题是在初始化的时候有所不同。
如果是第一种问法,要求恰好装满背包,那么在初始化时除了F[0]为0,其他F[1..V]均设为负无穷,这样就可以保证最终得到的F[V]是一种恰好装满背包的最优解。
如果并没有要求必须把背包装满,而是只希望价格尽量大,初始化时应该将F[0….V]全部设为0。
这是为什么呢?可以这样理解:初始化的F数组事实上就是在没有任何物品可以放入背包时的合法状态。如果要求背包恰好装满,那么此时只有容量为0的背包可以在什么也不装且价值为0的情况下被”恰好装满”,其他容量的背包均没有合法的解,属于未定义的状态,应该被赋值为负无穷了。如果背包并非必须被装满,那么任何容量的背包都有一个合法解”什么都不装“,这个解的价值为0,所以初始化时状态的值也就全部为0了。
这个小技巧完全可以推广到其他类型的背包问题,后面也就不再对进行状态转移之前的初始化进行讲解。剩下的就是一些背包问题的变形以及扩展,那些题就需要随机应变了,下面会有例题。下面上例题:
采药问题
题目描述
医师把他带到一个到处都是草药的山洞里对他说:“孩子,这个山洞里有一些不同的草药,采每一株都需要一些时间,
每一株也有它自身的价值。我会给你一段时间,在这段时间里,你可以采到一些草药。
如果你是一个聪明的孩子,你应该可以让采到的草药的总价值最大。”  如果你是辰辰,你能完成这个任务吗?
输入
输入的第一行有两个整数T(1  < =  T  < =  1000)和M(1  < =  M  < =  100),用一个空格隔开,
T代表总共能够用来采药的时间,M代表山洞里的草药的数目。接下来的M行每行包括两个在1到100之间(包括1和100)的整数,
分别表示采摘某株草药的时间和这株草药的价值。
输出
输出包括一行,这一行只包含一个整数,表示在规定的时间内,可以采到的草药的最大总价值。
样例输入
70 3
71 100
69 1
1 2
样例输出
3
提示
对于30%的数据,M  < =  10;对于全部的数据,M  < =  100。

代码:
#include<stdio.h>
#include<string.h>
int dp[1001];
int main()
{
	int time,m,i,j,t,v;
	scanf("%d%d",&time,&m);
	memset(dp,0,sizeof(dp));
	for(i=1;i<=m;i++)
	{
		scanf("%d%d",&t,&v);
		for(j=time;j>=t;j--)
			dp[j]=dp[j]>(dp[j-t]+v)?dp[j]:(dp[j-t]+v);
	}
	
  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值