装箱问题(dp)

问题描述
  有一个箱子容量为V(正整数,0<=V<=20000),同时有n个物品(0<n<=30),每个物品有一个体积(正整数)。
  要求n个物品中,任取若干个装入箱内,使箱子的剩余空间为最小。
输入格式
  第一行为一个整数,表示箱子容量;
  第二行为一个整数,表示有n个物品;
  接下来n行,每行一个整数表示这n个物品的各自体积。
输出格式
  一个整数,表示箱子剩余空间。
  样例输入
  24
  6
  8
  3
  12
  7
  9
  7
样例输出
       0
       关于这一题,有两种解法,一种是利用一维数组dp[]来解决,另一种是利用二维数组dp[][]来解决,我们先来讲第二种,比较好理解
       dp[i][j]表示在前i个物品在容量为j的体积中所存放的最大价值,只不过这里的最大价值等价与最大体积,我们在这里应该知道这应该是一个背包问题,对于一个物品,存在着两种情况,放与不放,如果不放则dp[i][j] == dp[i-1][j],因为你们没有放物体,则在逻辑上等价于前一物体,如果放则dp[i][j] == dp[i-1][j-a[i]]+a[i],在前一状态的基础上,加入物体,剩余空间必然减少,价值增大,但是两者又是等价,则可以如是,这一点很难想,也应该是我们所说的背包问题,具体问题请看代码:

#include<iostream>
using namespace std;
int v, n, a[31], dp[31][10000];
/*
	dp[i][j]表示前i个物品放入容量为j的背包中所得到的最大值
	采用二维数组更好理解一些,但是其空间与时间的开销更大 
*/
int main()
{
	int i, j;
	cin>>v>>n;
	for(i = 1; i <= n; i++)
		cin>>a[i];
	for(i = 1; i <= n; i++)
		dp[i][0] = 0;
	for(j = 1; j <= v; j++)
		dp[0][j] = 0;
	for(i = 1; i <= n; i++)
	{
		for(j = 1; j <= v; j++)
		{
			if(j < a[i])//装不下 
				dp[i][j] = dp[i-1][j];
			else
				dp[i][j] = max(dp[i-1][j], dp[i-1][j-a[i]]+a[i]);
		}	
	}
	printf("%d", v-dp[n][v]);
	return 0;	
} 

但是这会超时,只有80%的正确率。
       采用一种更简单的方式,只需要用一维数组即可,dp[j]表示在容量剩余为j的体积中所能装入的最大价值,同样有放与不放两种状态,不放则不变即dp[j] == dp[j],放则dp[j] = dp[j-a[i]]+a[i],也是属于背包问题,剩余容量减少,但是价值增大,两者也是等价,具体问题请看代码:

#include<iostream>
#include<cstring>
using namespace std;
int v, n, a[31], dp[20005]; 
int main()
{
	int i, j;
	cin>>v>>n;
	memset(dp, 0, sizeof(dp));
	for(i = 0; i < n; i++)
	{
		cin>>a[i];
		/*
			针对一个物品只有两种状态,装与不装,这里的j表示剩余容量
			如果装箱,则背包价值为dp[j-a[i]]+a[i],如果不装箱,则为dp[j]
			所以dp[j] = max(dp[j], dp[j-a[i]]+a[i])(伪背包问题)
			//不太好理解可以采用二维数组解题 
		*/
		for(j = v; j >= a[i]; j--)
		{
			dp[j] = max(dp[j], dp[j-a[i]]+a[i]);
		}
	}
	printf("%d", v-dp[v]); 
	return 0;
}

如果还是不太好理解可以先查询关于背包问题的解决方案。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值