這周的問題終於有些難度了,終於不是一眼看過去就有能寫出大概的題目了,還有就是,我又找不到題目了,所以去網上扒了一下,英語的:
| 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);
