0-1背包问题及变种

本文详细介绍了0-1背包问题的动态规划解决方案,包括基本思想、状态转移方程,并提供了递归和迭代两种算法实现。此外,还探讨了问题的两个变种:恰好装满背包和完全背包问题,给出了相应的优化和解法。同时,文章包含了腾讯笔试题中类似背包问题的非递归解法分析。
摘要由CSDN通过智能技术生成

0-1背包问题:

       有N件物品和一个容量为V的背包。第i件物品的费用是c[i],价值是w[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。

       这个问题的特点是:每种物品只有一件,可以选择放或者不放。

算法基本思想:

      利用动态规划思想 ,子问题为:f[i][v]表示前i件物品恰放入一个容量为v的背包可以获得的最大价值。

      其状态转移方程是:f[i][v]=max{f[i-1][v],f[i-1][v-c[i]]+w[i]}   //这个方程非常重要,基本上所有跟背包相关的问题的方程都是由它衍生出来的。

      解释一下上面的方程:“将前i件物品放入容量为v的背包中”这个子问题,如果只考虑第i件物品放或者不放,那么就可以转化为只涉及前i-1件物品的问题,即1、如果不放第i件物品,则问题转化为“i-1件物品放入容量为v的背包中”;2、如果放第i件物品,则问题转化为“i-1件物品放入剩下的容量为v-c[i]的背包中”(此时能获得的最大价值就是f [i-1][v-c[i]]再加上通过放入第i件物品获得的价值w[i])。则f[i][v]的值就是1、2中最大的那个值。

(注意:f[i][v]有意义当且仅当存在一个前i件物品的子集,其费用总和为v。所以按照这个方程递推完毕后,最终的答案并一定是f[N] [V],不一定是唯一的最大值,也可以是f[N][0..V]的最大值。

 以上概念和算法基本思想来源于blog:http://www.cnblogs.com/fly1988happy/archive/2011/12/13/2285377.html

以下为算法代码:是个不断优化的过程。首先(1)给出了递归和迭代的思想,(2)然后对迭代的算法代码进行空间优化。(3)然后给出了该问题的变种:恰好装满背包和完全背包问题。

(1)递归方法:

// 0-1 背包问题递归方法  回溯求最佳解
int packageRecursion(int c, int n)
{
	if(n == N) 
		return (c < weight[n])? 0 : value[n];
	if(c < weight[n]) 
		return packageRecursion(c, n+1);
	return max(packageRecursion(c, n+1), packageRecursion(c - weight[n], n+1) + value[n]);
}

(2)迭代方法:

//  0-1 背包问题迭代方法 
void packageIteraction()
{
	int **F;
	F = new int*[N+1];   // 申请内存空间
	int i;
	for(i = 0; i < N+1; i++)
	{
		F[i] = new int [C+1];
		
	}

	int j;
	for(i = 0 ; i < N+1; i++)
	{
		for(j = 0; j < C+1; j++)
		{
			F[i][j] = 0;              // 初始化
		}
	}

	// 正好装满背包 加上这几行
	/*for(i = 0 ; i < N+1; i++)
	{
		for(j = 1; j < C+1; j++)
		{
			F[i][j] = min;             
		}
	}*/


	for(i = 1; i < N+1; i++)
	{
		for(j = weight[i]; j < C+1; j++)
		{
			F[i][j] = F[i-1][j] > (F[i-1][j-weight[i]]+value[i])? F[i-1][j] : (F[i-1][j-weight[i]]+value[i]);
		}
	}
	if(F[N][C] > 0)
	{
		cout << "the opt value:" << F[N][C] << endl; 
		j = C;                //  回溯 遍历出所选择的节点
		for(i = N; i >= 1; i--)
		{
			if(F[i][j] == (F[i-1][j-weight[i]]+value[i]))
			{
				cout << i << "weight=: " <<
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值