完全背包总结

完全背包问题:

 

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

基本思路:

 这个问题和我们刚解决的01背包问题很像,不同的是该问题中的物品每一件有若干件,而01背包中的每一件物品只有一件.

 

动态规划(DP):

        1) 子问题定义:F[i][j]表示前i物品中选取若干件物品放入剩余空间为j的背包中所能得到的最大价值。

        2) 根据第i物品放多少件进行决策,我们可以将该问题转化为01背包问题求解,对于特定的容量,每一件物品最多放V/C[i]件,然后按照01背包dp

                        

dp[i][j]=max(dp[i][j],dp[i-1][j-k*need[i]]+k*value[i]);

 


      (2-1)

 

 

        其中F[i-1][j-K*C[i]]+K*W[i]表示前i-1物品中选取若干件物品放入剩余空间为j-K*C[i]的背包中所能得到的最大价值加上k件第i物品;

       设物品种数为N,背包容量为V,第i物品体积为C[i],第i物品价值为W[i]。

       与01背包相同,完全背包也需要求出NV个状态F[i][j]。但是完全背包求F[i][j]时需要对k分别取0,…,j/C[i]求最大F[i][j]值,耗时为j/C[i]。那么总的时间复

杂度为O(NV∑(j/C[i]))

 

#include<bits/stdc++.h>
using namespace std; 
const int maxn=555;
int dp[maxn][111111];
int need[maxn],value[maxn];
int n,m;
int main()
{
	int i,j,k;
	while(~scanf("%d %d",&n,&m))
	{
		memset(dp,0,sizeof(dp));
		for(i=1;i<=n;i++)
			scanf("%d %d",&need[i],&value[i]); 
		for(i=1;i<=n;i++)
		{
			for(j=0;j<=m;j++)
			{
				for(k=0;k*need[i]<=j;k++)	
					dp[i][j]=max(dp[i][j],dp[i-1][j-k*need[i]]+k*value[i]);
			}
		}
		printf("%d\n",dp[n][m]);
	}
	return 0;
}
	

 

 

 

  简单优化:

        若两件物品满足C[i] ≤C[j]&&W[i] ≥W[j]时将第j种物品直接筛选掉。因为第i种物品比第j种物品物美价廉,用i替换j得到至少不会更差的方案。

       这个筛选过程如下:先找出体积大于背包的物品直接筛掉一部分(也可能一种都筛不掉)复杂度O(N)。利用计数排序思想对剩下的物品体积进行

排序,同时筛选出同体积且价值最大的物品留下,其余的都筛掉(这也可能一件都筛不掉)复杂度O(V)。整个过程时间复杂度为O(N+V)

 

       转化为01背包:

       因为同种物品可以多次选取,那么第i种物品最多可以选取V/C[i]件价值不变的物品,然后就转化为01背包问题。整个过程的时间复杂度并未减少。

如果把第i种物品拆成体积为C[i]×2k价值W[i]×2k的物品,其中满足C[i]×2k≤V。那么在求状态F[i][j]时复杂度就变为O(log2(V/C[i]))。整个时间复杂度就

变为O(NVlog2(V/C[i]))

 

时间复杂度优化为O(NV)

将原始算法的DP思想转变一下。

设F[i][j]表示出在前i种物品中选取若干件物品放入容量为j的背包所得的最大价值。那么对于第i种物品的出现,我们对第i种物品放不放入背包

进行决策。如果不放那么F[i][j]=F[i-1][j];如果确定放,背包中应该出现至少一件第i种物品,所以F[i][j]种至少应该出现一件第i种物品,

即F[i][j]=F[i][j-C[i]]+W[i]。为什么会是F[i][j-C[i]]+W[i]?因为我们前面已经最大限度的放了第i件物品,如果能放就放这最后的一件,

(或者理解为前面已经往背包中放入了第i件物品,我们每一次只增加一件的往背包里放,而且只能增加一件,多了放不下)

举个例子:

比方有重量为2的物品, dp[i][2]的时候放了一件了,当dp[i][4]的时候,dp[i][4]=max(dp[i-1][4],dp[i][4-2]+w[i]) 最多一件了

状态方程为:

                           (2-2)

 

 

#include<bits/stdc++.h>
using namespace std; 
const int maxn=555;
int dp[maxn][111111];
int need[maxn],value[maxn];
int n,m;
int main()
{
	int i,j,k;
	while(~scanf("%d %d",&n,&m))
	{
		memset(dp,0,sizeof(dp));
		for(i=1;i<=n;i++)
			scanf("%d %d",&need[i],&value[i]); 
		for(i=1;i<=n;i++)
		{
			for(j=0;j<=m;j++)
			{
				if(j>=need[i])
				dp[i][j]=max(dp[i-1][j],dp[i][j-need[i]]+value[i]);//注意和01背包的区别,这里是dp[i][j-need[i]]+value[i]
				else
				dp[i][j]=dp[i-1][j];
			}
		}
		printf("%d\n",dp[n][m]);
	}
	return 0;}

 

 

 

 

 

 

优化空间复杂度为O(V)

        和01背包问题一样,完全背包也可以用一维数组来保存数据。算法样式和01背包的很相似,唯一不同的是对V遍历时变为正序,而01背包为逆序

。01背包中逆序是因为F[i][]只和F[i-1][]有关,且第i的物品加入不会对F[i-1][]状态造成影响。而完全背包则考虑的是第i物品的出现的问题,

第i种物品一旦出现它势必应该对第i种物品还没出现的各状态造成影响。也就是说,原来没有第i种物品的情况下可能有一个最优解,现在第i种物品

出现了,而它的加入有可能得到更优解,所以之前的状态需要进行改变,故需要正序。

 

#include<bits/stdc++.h>
using namespace std; 
const int maxn=555;
int dp[111111];
int need[maxn],value[maxn];
int n,m;
int main()
{
	int i,j,k;
	while(~scanf("%d %d",&n,&m))
	{
		memset(dp,0,sizeof(dp));
		for(i=1;i<=n;i++)
			scanf("%d %d",&need[i],&value[i]); 
		for(i=1;i<=n;i++)
		{
			for(j=need[i];j<=m;j++)
			{
				if(j>=need[i])
				  dp[j]=max(dp[j],dp[j-need[i]]+value[i]);
				}
		}
		printf("%d\n",dp[m]);
	}
	return 0;
}

 

 

 

 

 

 

感谢!http://blog.csdn.net/wumuzi520/article/details/7014830

 

博主个人公众号开通啦,平时主要分享一些机器学习、深度学习等的论文和方法,以及算法与数据结构、大厂经验贴等!欢迎大家关注,一起交流进步!

在这里插入图片描述

 

  • 8
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 8
    评论
完全背包问题是一个经典的动态规划问题,它与01背包问题类似,但有一个重要的区别。在完全背包问题中,每种物品可以选择无限次放入背包中,而在01背包问题中,每种物品只能选择一次放入背包中。 解决完全背包问题的一种常见方法是将其转化为01背包问题。根据引用[3]中的思路,我们可以将每种物品拆分成多件只能选0件或1件的01背包中的物品。具体做法是,对于第i种物品,我们将其拆分成⌊V /Ci⌋件费用和价值均不变的物品,然后求解这个01背包问题。 在求解过程中,我们需要确定状态变量(函数)和状态转移方程。状态变量可以定义为dp[i][j],表示前i种物品放入容量为j的背包中所能获得的最大价值。状态转移方程可以表示为dp[i][j] = max(dp[i-1][j-k*Ci] + k*Wi),其中k表示第i种物品的数量。 边界条件是dp[0][j] = 0,表示没有物品可选时,背包的价值为0;dp[i][0] = 0,表示背包容量为0时,无法放入任何物品。 通过以上的分析,我们可以得到完全背包问题的动态规划解法。具体的代码实现和优化可以参考引用[1]和引用[2]中的内容。 总结起来,完全背包问题是一个经典的动态规划问题,可以通过将其转化为01背包问题来求解。在求解过程中,需要确定状态变量和状态转移方程,并考虑边界条件。通过动态规划的方法,可以高效地解决完全背包问题。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Marcus-Bao

万水千山总是情,只给五角行不行

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值