Description
一个工厂制造的产品形状都是长方体,它们的高度都是h,长和宽都相等,一共有六个型号,他们的长宽分别为1*1, 2*2, 3*3, 4*4, 5*5, 6*6。这些产品通常使用一个 6*6*h 的长方体包裹包装然后邮寄给客户。因为邮费很贵,所以工厂要想方设法的减小每个订单运送时的包裹数量。他们很需要有一个好的程序帮他们解决这个问题从而节省费用。现在这个程序由你来设计。
Input
输入文件包括几行,每一行代表一个订单。每个订单里的一行包括六个整数,中间用空格隔开,分别为1*1至6*6这六种产品的数量。输入文件将以6个0组成的一行结尾。
Output
除了输入的最后一行6个0以外,输入文件里每一行对应着输出文件的一行,每一行输出一个整数代表对应的订单所需的最小包裹数。
Sample Input
0 0 4 0 0 1
7 5 1 0 0 0
0 0 0 0 0 0
Sample Output
2
1
题目解析
这道题是贪心的经典题,可以作为初学的练习题目。
首先是处理多组数据——用无限循环(while(true) 或 for(;;)),在内部定义一个bool变量Break 初值为true,输入的同时,判断当前输入数据是否有非零数,若有,把Break改为false。最后,如果Break保持true不变,则break退出无限循环。
然后在内部编写程序。这里有两种思想,作者的较为易懂,先讲解这一种:
由于放置各种不同型号的盒子时区别太大,我把每一个型号分开放置。但是我们需要决定一个放置顺序——我们知道越小的盒子是越容易放置的,而若小盒子占用的位置太多,大盒子则无法放置,因此大盒子要优先放置。
首先放置6 * 6的盒子,很明显,一个盒子必须占用一个箱子,并且不能放置其他的盒子!所以6 * 6占用的箱子的数目就是它本身的数目。
再放置5 * 5的盒子。同样,一个盒子就需要一个箱子,但是会留下一些空隙,这些位置还能放置11个1 * 1的盒子,为了保证不浪费,我们要尽量把箱子塞满。那么放置n个5 * 5盒子所需要 11n 个1 * 1盒子。于是我们在1 * 1 盒子的原本数目中减去这些,不用担心负数。
4 * 4 依然每个盒子要占一个箱子,会有20格的空隙,能放置5个 2 * 2 箱子,也能放置20个 1 * 1 箱子。这时我们根据优先放置大盒子的规则,要先用 2 * 2 的盒子填好,若没有 2 * 2 箱子,但还有空位,就用 1 * 1 的盒子来填。
3 * 3 的盒子最复杂。首先4个 3 * 3 盒子能把一个箱子填满,而余下部分同样需要一个箱子,那么它需要的箱子数量为它的数量除以4过后向上取整的结果。由于箱子中放置的 3 * 3 盒子的数量不同,2 * 2盒子能够放置的个数是难以确定的,因此我们可以用一个数组 three_two,three_two[i]表示有i个 3 * 3 盒子时,可以放置的 2 * 2 盒子的个数。而 1 * 1 的盒子的个数则是36(箱子大小)减9(3 * 3 盒子大小)乘 3 * 3 盒子个数减4(2 * 2盒子大小)乘 2 * 2 盒子个数。
1 * 1 盒子与 2 * 2 盒子可以一起计算,可以把4个 1 * 1 盒子算作一个 2 * 2 盒子,剩余的 1 * 1 盒子也算作一个 2 * 2 盒子。所需箱子为 2 * 2 盒子的个数除以9所得的结果向上取整。
另外一种更加简洁,但较为复杂:
从上面的分析,我们知道—— 6 * 6 、 5 * 5 、 4 * 4 以及 3 * 3 的数量除以4向上取整的数量之和是它们必须占用的箱子数量,于是我们可以预先算出这一结果。我们把 1 * 1 和 2 * 2 的盒子用于“塞缝”。对于 2 * 2 的盒子,可以“给 4 * 4 盒子塞缝”,一个4 * 4 盒子的空隙能用5个 2 * 2 盒子填满;3 * 3 盒子空隙所需要的 2 * 2 盒子个数可以用一个数组存。1 * 1 的盒子用来最后填缝。
若空隙已经填满了,还剩余了 1 * 1 和 2 * 2 的盒子,同样按照作者的做法,将 1 * 1 处理成 2 * 2 盒子,按照9个 2 * 2 盒子装满1个箱子的规则,计算出答案。
样例程序
Accepted 作者的做法:
/*Lucky_Glass*/
#include
int main()
{
while(true)
{
bool Break=true;
int box[7]={},ans=0;
for(int i=1;i<=6;i++)
{
scanf("%d",&box[i]);
if(box[i]) Break=false;
}
if(Break) break;
/*six*/
ans+=box[6];
box[6]=0;
/*five*/
ans+=box[5];
box[1]-=box[5]*11;
box[5]=0;
/*four*/
ans+=box[4];
if(box[2]>=5*box[4])
box[2]-=5*box[4];
else
{
box[1]-=(box[4]*5-box[2])*4;
box[2]=0;
}
/*three*/
ans+=(box[3]+3)/4;
int three_two[4]={0,5,3,1},box3=box[3]%4;
box[3]=0;
if(box[2]>=three_two[box3])
{
box[2]-=three_two[box3];
box[1]-=9*(4-box3)-three_two[box3]*4;
}
else
{
box[1]-=9*(4-box3)-box[2]*4;
box[2]=0;
}
/*two*/
if(box[1]>0) box[2]+=(box[1]+3)/4;
ans+=(box[2]+8)/9;
printf("%d\n",ans);
}
return 0;
}
Accepted 别人的做法(一开始看不懂):
#include
int main()
{
int N,a,b,c,d,e,f,y,x;
int u[4]={0,5,3,1};
while(1)
{
scanf("%d%d%d%d%d%d",&a,&b,&c,&d,&e,&f);
if (a==0 && b==0 && c==0 && d==0 && e==0 && f==0)
break;
N=f+e+d+(c+3)/4;
y=5*d+u[c%4];
if(b>y) N+=(b-y+8)/9;
x=36*N-36*f-25*e-16*d-9*c-4*b;
if(a>x) N+=(a-x+35)/36;
printf("%d\n",N);
}
return 0;
}