P1049 [NOIP 2001 普及组] 装箱问题
题目描述
有一个箱子容量为 V V V,同时有 n n n 个物品,每个物品有一个体积。
现在从 n n n 个物品中,任取若干个装入箱内(也可以不取),使箱子的剩余空间最小。输出这个最小值。
输入格式
第一行共一个整数 V V V,表示箱子容量。
第二行共一个整数 n n n,表示物品总数。
接下来 n n n 行,每行有一个正整数,表示第 i i i 个物品的体积。
输出格式
- 共一行一个整数,表示箱子最小剩余空间。
输入输出样例
输入 #1
24
6
8
3
12
7
9
7
输出 #1
0
分析:
- 箱子的容量是24。
- 共有6个物品,体积分别是8、3、12、7、9、7。
- 我们可以通过尝试不同的组合来找到一种使箱子剩余空间最小的选择方式。在这个例子中,可以选择体积为8、7和9的三个物品放入箱子,它们的总体积正好是24,所以箱子的剩余空间是0。
因此,输出结果为0
,表示在这种情况下,可以完全填满箱子,没有剩余空间。这个问题可以通过动态规划等方法来解决,以确保找到最优解。
解决方法:
二维方法
#include<bits/stdc++.h>
#define N 31
#define V 20000
using namespace std;
//dp[i][j] 的含义 从 0-i 容量为j 最大能装多少
int dp[N][V];
int x, v, n;
int main () {
cin >> v >> n;
for (int i = 1; i <= n; i++) {
cin >> x;
for (int j = 1; j <= v; j++) {
if (j >= x)
dp[i][j] = max(dp[i-1][j], dp[i-1][j-x] + x);
else
dp[i][j] = dp[i-1][j];
}
}
cout << v- dp[n][v] << endl;
}
求解过程分析
首先 对于第一行分析,只取或者不取第一个物品
一维方法,参考了一篇博主的博客,我们在计算二维的时候,
01 背包问题需要注意的问题
就是假设dp[i]的含义是 可以承重i的背包可以放物品的最大体积,然后假设是正序遍历,就是从a[i]到v,当前物品的体积是2,我就更新了dp[2],当处理dp[4]的时候,因为dp[2]已经被更新了,因此可能会再次选取这个体积为2的物品相当于一个物品 放了多次,就变成什么完全背包了,
#include<bits/stdc++.h>
#define N 31
#define V 20000
using namespace std;
//dp[i][j] 的含义 从 0-i 容量为j 最大能装多少
int dp[V],a[N];
int x, v, n;
int main () {
cin >> v >> n;
for(int i = 1; i <= n; i++){
cin >> x;
for(int j = v; j >= a[i]; j--)
if(j >= x)
dp[j] = max(dp[j], dp[j-x] + x);
}
cout << v-dp[v] << endl;
return 0;
}