竞赛题目讲解-【Central Europe 1996】装箱问题
来源:互联网 发布:高斯步枪 知乎 编辑:程序博客网 时间:2024/06/05 21:15
【Central Europe 1996】装箱问题
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<cstdio>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<cstdio> 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;}
The End
Thanks for reading
- 竞赛题目讲解-【Central Europe 1996】装箱问题
- 竞赛题目讲解-【Northeastern Europe 2002, Far-Eastern Subregion】最长上升子序列
- 【poj 1144】Network 【Central Europe 1996】
- Sticks(Central Europe 1995)
- 竞赛题目讲解
- Central Europe 1996 / UVa 311 / POJ 1017 Packets (贪心)
- Central Europe 2005 Wild West ( POJ 2944 )
- Regionals 2014 >> Europe - Central >> 6934 - Good morning!
- Central Europe Regional Contest 2014 [Gym
- Central Europe Regional Contest 2014 B [Gym
- 【poj 1365】 Prime Land 【Central Europe 1997】
- 【poj 1511】 Invitation Cards 【Central Europe 1998】
- 竞赛题目讲解-【Standard IO】产生数
- 竞赛题目讲解-【Japan 2002 Kanazawa】碎纸机
- 装箱问题(NOIP竞赛原题)(动态规划)
- 装箱问题(NOIP竞赛原题)(动态规划)
- POJ 1365 / Central Europe 1997 Prime Land (数论)
- Central Europe Regional Contest 2012 Problem C: Chemist’s vows
- SQL Server 学习笔记之Collation(校对)
- 一周科技要闻
- 关于醉驾的想去没去成,去了没撞人,去了撞了,该受到怎样的谴责的理由
- QNX系统的ftp调试,连接FTP调试-QNX的PC104调试ftp
- BZOJ[1455]罗马游戏 可并堆
- 竞赛题目讲解-【Central Europe 1996】装箱问题
- 【JZOJ 5296】【清华集训2017模拟】Sequence
- NG机器学习week6 Advice for Applying Machine Learning
- lr相关
- Spring笔记-Spring的bean
- Akka 实践(二)- java开发demo1
- google地图
- Java中list对象的三种遍历方式
- CodeForces 548B 模拟连续的技巧。