描述
有一个箱子容量为v(正整数,o≤v≤20000),同时有n个物品(o≤n≤30),每个物品有一个体积 (正整数)。要求从 n 个物品中,任取若千个装入箱内,使箱子的剩余空间为最小。
格式
输入格式
第一行,一个整数,表示箱子容量;
第二行,一个整数,表示有n个物品;
接下来n行,分别表示这n个物品的各自体积。
输出格式
一个整数,表示箱子剩余空间。
样例1
样例输入1
24
6
8
3
12
7
9
7
样例输出1
0
限制
每个测试点1s
来源
noip2001普及组第四题
解题思路:
这题其实就是把 01 背包变换了一下,我们可以先求出它能装得下的最大容量,然后用背包容量减去最大容量,剩下的就自然是剩余的最小容量了。
所以,就是先用 01 背包的状态转移方程,求出能使用的最大容量。
这时,01背包的方程就要稍作修改
原来是这样的 f[i][j] = max(f[i - 1][j],f[i - 1][j - w[i]] + c[i])
w 存放物品的体积, c 存放物品的价值
这时,要改为:f[i][j] = max(f[i - 1][j],f[i - 1][j - w[i]] + w[i]);
就是把后面的 + 物品的价值修改为 + 物品的体积。
因为这里要求的是最大的容量,而不是最大的价值。
最后再用总的容量 m 减去 求得的最大容量 就可以了
#include <iostream>
#include <algorithm>
using namespace std;
int f[35][20005];
int w[35];
int main()
{
ios::sync_with_stdio(false);
int n,m;
cin >> m >> n;
for (int i = 1; i <= n; ++i)
{
cin >> w[i];
}
for (int i = 1; i <= n; ++i)
{
for (int j = 0; j <= m; ++j)
f[i][j] = m;
}
for (int i = 1; i <= n; ++i)
{
for (int j = 0; j <= m; ++j)
{
//cout << f[i][j] << " ";
if (j >= w[i])
{
f[i][j] = max(f[i - 1][j],f[i - 1][j - w[i]] + w[i]);
}
else
f[i][j] = f[i - 1][j];
}
}
cout << m - f[n][m] << endl;
return 0;
}
这个还可以像 01 背包那样用一维进行空间上的优化,使用一维数组达到目的。
f [j] = max(f [j],f [j - w[i]] + c[i])
这个是 01 背包的使用一维数组时的状态转移方程
下面的是这个问题的一维数组优化的状态转移方程
f [j] = max(f [j],f [j - w[i]] + w[i])
注意:循环的顺序也要进行修改,因为是使用一维数组,所以循环顺序要修改
原来是从 1 一直 到 m,使用一维时要从 m 到 0 。