codevs P1014 装箱问题

装箱问题

题目描述 Description
有一个箱子容量为V(正整数,0<=V<=20000),同时有n个物品(0<n<=30),每个物品有一个体积(正整数)。
要求n个物品中,任取若干个装入箱内,使箱子的剩余空间为最小。

输入描述 Input Description
一个整数v,表示箱子容量
一个整数n,表示有n个物品
接下来n个整数,分别表示这n 个物品的各自体积

输出描述 Output Description
一个整数,表示箱子剩余空间。

样例输入 Sample Input样例输出 Sample Output
24 60
8 3 12 7 9 7

题解

作为经典的DP还是值得思考的。
这个问题是以背包问题为基础,请先弄懂这个01背包再来看此题!

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxm=30000;
int v,n,d[maxm];
int dp[50][30000]; 

int main(){
	std::ios::sync_with_stdio(false);
	cin>>v>>n;
	for(int i=1;i<=n;i++)
		cin>>d[i];
		
	for(int i=1;i<=v;i++){
		if(i>=d[1]) dp[1][i]=dp[1][i]-d[1]+i;
		else dp[1][i]=i;
	}
		
	for(int i=2;i<=n;i++){ 
		for(int j=1;j<=v;j++){
			dp[i][j]=j;
			if(j>=d[i]){
				dp[i][j]=min(dp[i-1][j],dp[i-1][j-d[i]]);
			}else dp[i][j]=dp[i-1][j];
		}
	}
	
	cout<<dp[n][v];
	return 0;
}

i 枚举的是选择前 i 个物品,j 枚举的是体积。 f [ i ] [ j ] 就是选前 i 个物品在体积为 j 时的最小剩余体积,
当我们在一定的体积下选择物品时通常做两种考虑——选和不选。
如果说,你当前选择的物品比背包空间还大,那就只有dp [ i ] [ j ] = dp [ i - 1 ] [ j ] ; 继承前一种状态,只能不选。代码如下:

else dp[i][j]=dp[i-1][j];

为什么可以直接把前一种状态赋值过来?你反正 j 体积下第 i 个是不选的,那是不是等同于就选了 j 体积下前 i - 1 个物品?

如果你当前选择的物品比背包空间小,那就再多考虑一种要选的情况:
如果选了第 i 个个物品,那我们就考虑第 i-1 个物品背包体积为你选了这个物品后的体积(j-d[i])的最小。并在选与不选之前取一个最小值。
所以状态转移方程就是这个:

dp[i][j]=min(dp[i-1][j],dp[i-1][j-d[i]]);

当仅仅选择第一个物品时是特殊情况(因为 i - 1 = 0 ),所以特殊处理。

for(int i=1;i<=v;i++){
		if(i>=d[1]) dp[1][i]=dp[1][i]-d[1]+i;
		else dp[1][i]=i;
	}

如果能弄懂状态转移方程,这个特殊处理我也不必多言。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值