这周的问题终于有些难度了,终于不是一眼看过去就有能写出大概的题目了,还有就是,我又找不到题目了,所以去网上扒了一下,英语的:
Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 28329 | Accepted: 9291 |
Description
Input
Output
Sample Input
0 0 4 0 0 1 7 5 1 0 0 0 0 0 0 0 0 0
Sample Output
2 1
看完题我第一反应就是贪心,用最少的箱子装最多的货物。确定了贪心之后便开始思考,如何解题。首先每一新箱子都有 6*6 = 36 的空间,然后看货物,细细一想,发现 边长大于3的货物都需要单独开一个箱子,所以便有了第一行代码
sum += goods4 + goods5 + goods6;
又反复的思考了一下3的情况 一个 6*6的箱子能够装4个3*3的箱子。所以上面的算法就可以修改成
sum += goods4 + goods5 + goods6 + ((goods3 - 1) / 4 + 1);//向上取整,多出来的一个必须多开一个箱子
为什么多出来的3*3货物必须多开一个箱子呢,分析一下空间就可以了,题目中说物品高度相同,所以只需要考虑占地面积,5*5 和 4*4 的货物所占的盒子虽然还有空间,但是它们余下的空间只能够存放1*1或者2*2的货物,所以多出来的3*3必须额外开辟一个空间。到了这一步问题就来了,3*3的货物是4的倍数那最好,如果3*3的货物不是4的倍数,那么就必须额外开一个箱子,用来存放余下的3*3的货物,那么存放多余的的组成不成一件3*3的货物肯定会有多余空间,而且余数不止一种,我们就需要进行分类讨论。嗯好,我们来继续分析,现在3*3的货物是被全部放下了,但是由于3*3的货物不是 4 的倍数, 难么肯定就会有多余的空间,而且根据余数的不同肯定有不同的情况。那么余数有几种可能呢 ?唔,让我们来想一想,一个 箱子可以放4个3*3,那么x%4的可能只有4种吧,0、1、2、3 。
现在我们来分析一下 3*3 的情况,无剩余的情况就不分析了
画个图就可以直观的看到结果了:
由图可知:
1、当余下1个的时候还能装7个1*1和5个2*2,
2、当余下2个的时候还能装6个1*1和3个2*2,
2、当余下3个的时候还能装5个1*1和1个2*2,
得出相应的代码:
if (goods3 % 4 == 1) { spaceby1 += 7; spaceby2 += 5; } //余下1个3*3所余下的1*1和2*2的空间 if (goods3 % 4 == 2) { spaceby1 += 6; spaceby2 += 3; } //余下2个3*3所余下的1*1和2*2的空间 if (goods3 % 4 == 3) { spaceby1 += 5; spaceby2 += 1; } //余下3个3*3所余下的1*1和2*2的空间
处理完3*3的就简单了,我们按顺序去处理2*2的货物. 在这之前们需要求出有多少地方可以存储2*2的货物,5*5是无法存储2*2 的货物的,但是4*4的可以4*4的里面还可以存放5个2*2 所以我们需要加上goods2
4*5。好了2*2的空间算完,那还得分类论。
很显然分为3总情况:
1、刚好存下,皆大欢喜
2、存不下,还得开空间
3、有剩余,计算剩余空间
让2*2的空间数与货物数进行比较够的话,就不用额外开空间了不够的话直接开空间
代码如下:
spaceby2 += 5 * goods4; //装一个4*4的时候余下的1*1和2*2的空间 if (spaceby2 < goods2) //2*2的空间小于2*2的盒子 { //额外的2*2空间需要的箱子 sum += ((goods2 - spaceby2 - 1) / 9 + 1); }
余下1*1 的模仿2*2的流程即可,1*1剩余空间建议用总箱子数*36 - 被占用的空间这样就可以快速的得出1*1的空间而且不容易错,(2*2不用这个方法是因为5*5的碎片空间虽然足够但是呢,它边长就……6*6,放不下2*2)1*1的就不单独贴代码了
下面贴一下完整的代码(能自己写出来的先自己写一遍),记得分析数据大小:

#include <stdio.h> /** * @author 杨文蓁的小迷弟 * @note 算法作业3 * @date 2019/09/05 */ int main() { //北大OJ数据超过了正常的int,估计有一个50000的数据 unsigned int goods1, goods2, goods3, goods4, goods5, goods6; //1,2,3,4,5,6 while (scanf("%d %d %d %d %d %d", &goods1, &goods2, &goods3, &goods4, &goods5, &goods6) != EOF) { unsigned int sum = 0, spaceby1 = 0, spaceby2 = 0; //sum总箱子数,n余下放1x1的位置,m余下放2x2的位置 if (goods1 == 0 && goods2 == 0 && goods3 == 0 && goods4 == 0 && goods5 == 0 && goods6 == 0) { return 0; } sum += goods4 + goods5 + goods6 + ((goods3 +3) / 4); //最少需要开的箱子 if (goods3 % 4 == 1) { spaceby1 += 7; spaceby2 += 5; } //余下1个3*3所余下的1*1和2*2的空间 if (goods3 % 4 == 2) { spaceby1 += 6; spaceby2 += 3; } //余下2个3*3所余下的1*1和2*2的空间 if (goods3 % 4 == 3) { spaceby1 += 5; spaceby2 += 1; } //余下3个3*3所余下的1*1和2*2的空间 spaceby2 += 5 * goods4; //装一个4*4的时候余下的1*1和2*2的空间 if (spaceby2 <= goods2) //2*2的空间小于2*2的盒子 { //额外的2*2空间需要的箱子 sum += ((goods2 - spaceby2 + 8) / 9); } //余下了多少 1*1 的空间 spaceby1 = 36 * sum - 36*goods6 - 25*goods5 - 16*goods4 - 9*goods3 - 4*goods2; if (spaceby1 <= goods1) { sum += ((goods1 - spaceby1 + 35) / 36); } printf("%d\n", sum); } return 0; }
贴个python的代码:

#author: 杨文蓁的小迷弟 #date: 2019/9/5 while (1): s=input().split() box_sum = spaceby1 = spaceby2 = 0 flag = True for i in range(len(s)): if int(s[i]) != 0: flag = False if flag == True: exit() box_sum = int(s[5]) + int(s[4]) + int(s[3]) + (int(s[2])-1) // 4+1 if int(s[2])%4 == 1: spaceby1 += 5 spaceby2 += 7 if int(s[2])%4 == 2: spaceby1 += 6 spaceby2 += 3 if int(s[2])%4 == 3: spaceby1 += 5 spaceby2 += 1 spaceby2 += 5 * int(s[3]) if spaceby2 <= int(s[1]): box_sum += ((int(s[1])-spaceby2-1)//9 + 1) spaceby1 = 36*box_sum - 36*int(s[5]) - 25*int(s[4]) - 16*int(s[3]) - 9*int(s[2]) - 4*int(s[1]); if spaceby1 <= int(s[0]): box_sum += ((int(s[0])-spaceby1-1)//36 + 1) print(box_sum);