【小韦同学@神犇营-my1051-装箱问题】
题目:
描述
有一个箱子容量为 V(正整数,0 ≤ V ≤ 20000),同时有 n 个物品(0< n ≤ 30),每个物品有一个体积(正整数)。
要求 n 个物品中,任取若干个装入箱内,使箱子的剩余空间为最小。
输入
1个整数,表示箱子容量
1个整数,表示有 n 个物品
接下来 n 行,分别表示这 n 个物品的各自体积
输出
1个整数,表示箱子剩余空间。
输入样例1
24
6
8
3
12
7
9
7
输出样例1
0
题解:
/*********************************************************************
* 题目:神犇营-my1051-装箱问题
* 作者:小韦同学
* 邮箱:weichangying_wcy@163.com
* 题解:
思路:
从n个物体中任意选一些物体放入背包,要求背包可能的最小剩余空间。
我们需要考虑所有可能的物体选择组合,同时要求这个组合的总体积小于背包
的容积。然后对每种组合,计算对应的背包剩余空间,选择最小的。
我们可以从第1个物体开始,依次选择每个物体是否放入背包。
在做选择前,我们首先要考虑背包里是否还能放下这个物体,如果已经放不下了,
那我们没有选择的余地,只能不放;如果还能放下,我们可以选择放,也可以选择不放。
举个例子:物体的体积依次为3 6 5 ,背包容量为10
先考虑第一个物体 体积为3 此时背包容量为10 能放下
我们可以选择放入,则此时背包容量为10-3=7
也可以选择不放入,此时背包容量仍为10
在考虑完第一个物体后,这个问题会产生两个新的问题:
选择放入第一个后:剩下的物体体积为 6 5, 背包容量为7
选择不放入第一个后:剩下的物体体积为 6 5, 背包容量为10
不难看出,产生的新问题和最初的问题其实是类似的,具有相同的结构。
因此可以考虑递归的思想来解决这个问题。
形式化的定义这个问题:
物体1-n的体积为a1、a2...an,背包体积为V
我们只需要递归的考虑每个物体,直到第n个为止,看看背包剩余容积为多少
我们首先令最小的剩余体积R=V
对于第i个物体,假设此时的背包剩余体积为R,那么:
我们有两种选择:
放入i(前提是ai<R),背包剩余容积R=R-ai
不放入i,背包剩余容积R=R-0
此外,我们还需要为递归增加终止条件,即判断什么时候,递归结束。
根据问题可知,如果考虑所有n个物体,则需要结束。
注意:
*********************************************************************/
#include<bits/stdc++.h>
using namespace std;
const int MAX = 50;
int items[MAX];
bool judge[MAX];
int min_v = 2e4 + 10; // 用来记录箱子最小剩余空间
// 参数:枚举物品的下标,箱子剩余空间,箱子容量,物品个数
void put_items(int idx, int remain, int v, int n){
// 如果箱子剩余空间小于0
if(remain < 0) return;
if(remain < min_v){ // 若箱子剩余空间小于min_v
min_v = remain; // 更新箱子最小剩余空间
}
// 枚举每一个物品
for(int i = idx; i < n; i++){
if(!judge[i]){ // 若当前物品未装箱
judge[i] = true; // 表示标记该物品已装箱
// 递归调用函数
put_items(i+1, remain-items[i], v, n);
judge[i] = false; // 将该物品标记为未装箱
}
}
}
int main(){
int v, n;
cin >> v >> n;
for(int i = 0; i < n; i++) {
cin >> items[i];
judge[i] = false; // 表示物品未被装入
}
// 将物品体积升序排列
sort(items, items + n);
put_items(0, v, v, n);
cout << min_v;
return 0;
}
我是小韦同学,企者不立,跨者不行,每天进步一点点。
欢迎大家多多交流,如果发现有错误,请多指正。有疑问的同学也可以留言评论或者发邮件。
邮箱:weichangying_wcy@163.com