【题目来源】
http://poj.org/problem?id=1017
【问题描述】
有一个工厂制造的产品形状都是长方体,一共有6种型号,每种型号长方体的长和宽分别是1×1、2×2、3×3、4×4、5×5、6×6,高都是h。这些产品使用统一规格的箱子进行包装,箱子的长、宽和高分别是6、6和h。对于每个订单工厂希望用最少的箱子进行包装。每个订单包括用空格分开的6个整数,分别代表这6种型号的产品数量。输出是包装需要箱子的个数。
【输入数据】
输入文件包含若干行,每行表示一个订单。一个订单包含6个用空格分开的整数,分别表示产品1×1至产品6×6的个数。
最后一行6个零,表示输入结束。
【输出数据】
若干行,每行表示当前订单所需的最少箱子数。
【算法分析】
● 在本题中,虽然6种型号的产品及装产品的箱子都被描述为3维的,但由于它们的高度都一样,所以本题可以降为2维问题。即如何将某个订单中1×1、2×2、3×3、4×4、5×5、6×6的正方形放入6×6的正方形中,使得此订单可用最少的6×6正方形容纳。
● 6种规格产品的装箱情况分析,如下表所示:
1个箱子容纳的产品 | 剩余空间的装载情况 | |||
产品 | 个数 | 2×2 | 1×1 | 解释 |
6×6 | 1 | 0 | 0 | 无剩余空间 |
5×5 | 1 | 0 | 11 | 11个长度为1的产品 |
4×4 | 1 | 5 | 0 | 5个长度为2的产品 |
3×3 | 1 | 5 | 7 | 5个长度为2的产品+7个长度为1的产品 |
3×3 | 2 | 3 | 6 | 3个长度为2的产品+6个长度为1的产品 |
3×3 | 3 | 1 | 5 | 1个长度为2的产品+5个长度为1的产品 |
3×3 | 4 | 0 | 0 | 无剩余空间 |
2×2 | 9 | 0 | 0 | 无剩余空间 |
1×1 | 36 | 0 | 0 | 无剩余空间 |
通过观察上表可知,当不同规格、不同个数的产品装入6×6的正方形中后,剩余空间只能容纳长度为2的产品及长度为1的产品。特别地,当6×6的正方形中分别装入4,3,2,1个3×3规格的产品后,剩余空间最多可以装0,1,3,5个2×2规格的正方形。
● 本题可以用简单的模拟法来求解。但由于题目要求用最少的6×6正方形完成装箱,故需要用到贪心策略,即每次装箱时选择某个订单中规格最大的产品先装入,然后选择订单中剩余的规格最大的产品再装入,……,依次类推。
● 计算所需最少箱子数时,注意要向上取整。若求x/y向上取整的值,有两种方法:一种是ceil(x/y),另一种是(x+y-1)/y。
【算法代码】
#include <iostream>
using namespace std;
int main() {
int n1,n2,n3,n4,n5,n6; //count of 1*1~6*6
int one,two; //Remaining space for 1*1, 2*2
int sum; //The number of boxes required
while(1) {
cin>>n1>>n2>>n3>>n4>>n5>>n6;
if(n1+n2+n3+n4+n5+n6==0) break;
sum=n6+n5+n4+(n3+3)/4; //ceil(n3/4)
two=n4*5;
if(n3%4==3) {
two+=1;
} else if(n3%4==2) {
two+=3;
} else if(n3%4==1) {
two+=5;
}
if(two<n2) { //If have products 2
sum+=((n2-two)+8)/9; //ceil((n2-two)/9)
}
one=36*sum-36*n6-25*n5-16*n4-9*n3-4*n2;
if(one<n1) { //If have products 1
sum+=((n1-one)+35)/36; //ceil((n1-one)/36)
}
cout<<sum<<endl;
}
return 0;
}
/*
in:
0 0 4 0 0 1
7 5 1 0 0 0
0 0 0 0 0 0
out:
2
1
*/
注意:
本例代码,在POJ中提交会提示Output Limit Exceeded。