信息学奥赛一本通 1226:装箱问题 | OpenJudge NOI 4.6 19:装箱问题
【題目鏈接】
ybt 1226:裝箱問題
OpenJudge NOI 4.6 19:裝箱問題
【題目考點】
1. 貪心
【解題思路】
該題說是三維立方體,實際上無論是包裹還是產品,高度都是h,因而不用考慮高度,這實際上是二維平面上的問題。
1. 貪心選擇性質的證明
貪心選擇:選擇最大的可以裝入該包裹的產品裝入該包裹
假設所有最優解都不包含第一次的貪心選擇,即第一個包裹C中不包含最大的產品x。
最大的產品x一定存在于某個包裹內,記那個包裹為N。我們可以將N中的所有產品和C中的所有產品完全交換。總包裹數量不變,第一個包裹C中存在產品x,這與假設相悖,假設不成立,原命題得證。
是否做貪心選擇區別在于:當前拿到一個最大的可以裝入當前包裹C的產品x,是將這個產品放在當前包裹C中,還是將其放在一個新包裹N中。貪心選擇是將其放在當前包裹C中。
使用反證法:假設對所有最優解,在裝第k+1個產品時,當前關注的包裹C可以裝入的最大產品為x,此時不進行貪心選擇,不選擇x,接下來只會裝入大小小于x的產品。也可以說,當前包裹C中,產品x的數量不會更多。
下面考慮在N中包括x的部分產品能否和C中的一些產品或空位交換,且兩包裹仍能裝得下。如果可以,那么說明第k+1步進行了貪心選擇,選擇了產品x,總包裹數量不變,也是最優解。假設不成立,原命題得證。
- 如果N中x的數量大于C中x的數量,且x在C中與N中都是最大的產品,那么可以將N與C中的所有產品整體交換。
x為4*4、5*5、6*6都滿足這一情況?;駽中3*3的個數比N中3*3的個數更少。
例:x為5*5,在第k+1步往C中裝產品時,沒有按照貪心選擇將5*5的產品裝入C。后來5*5的產品裝入了N,C中又裝了一些產品。將C與N的所有產品交換后,C中存在貪心選擇,總包裹數仍然最少,說明存在最優解在第k+1步進行了貪心選擇,假設不成立,原命題得證。
以下為N中x的數量小于等于C中x的數量的情況: - 如果x是1*1的產品,那么C當時可以放1*1的產品但不放,存在一些位置空著,C中一定有可以放下1*1的空位??梢酝瓿山粨Q。
- 如果x是2*2的產品,那么C當時可以放2*2的產品但不放,去放1*1的產品或空著。那么在C中一定可以選擇出2*2的區域,其中可以是1*1的產品也可以是空位,與x進行交換。
- 如果x是3*3的產品,說明先前加入C的是若干個3*3的產品。
N中有2個3*3產品與至多3個2*2產品,此時,把N中的1個3*3與C中的2個2*2與1個1*1交換,結果為C中有3個3*3與1個2*2,N中有1個3*3與5個2*2,這種交換是可行的。
同理,如果N中有1個3*3與至多5個2*2,用N中的1個3*3交換C中的2個2*2與1個1*1是可行的。
例:將N中的紅色3*3產品x與C中的藍色兩個2*2產品與1個1*1產品進行交換。交換 后一些1*1產品位置發生變化。
如果待交換的產品沒有那么多,可以用空位代替。
例:將N中的紅色3*3產品x與C中的藍色兩個2*2產品與1個1*1產品進行交換。交換 后一些1*1產品位置發生變化。
- x不可能是4*4或更大的產品,如果是,C中可以放x但不放,C中的x只能是0個,而N中的x有1個,這是前面已經討論過的“如果N中x的數量大于C中x的數量”的情況。
因此N中包括x的部分產品總能和C中的一些產品或空位交換位置。說明第k+1步進行了貪心選擇,選擇了產品x,總包裹數量不變,也是最優解。因而假設不成立,原命題得證。
2. 具體做法
考慮各種情況下,剩下的空間最多可以放下幾個各種產品,總結成表格
| 1個6*6 | 0 | 0 | 0 |
| 1個5*5 | 0 | 0 | 11 |
| 1個4*4 | 0 | 5 | 20 |
| 1個3*3 | 3 | 5 | 27 |
| 2個3*3 | 2 | 3 | 18 |
| 3個3*3 | 1 | 1 | 9 |
| 無 | 4 | 9 | 36 |
此這基礎上,每多放一個2*2,1*1可放個數減4。
觀察規律,1*1可以放的個數就是總面積6*6減去所有放入其中的產品的總面積。
在已有3*3的情況下,每多放入一個3*3,2*2可以放入的個數減2。
這里只需要設數組記錄放入1個某大小產品后,其他大小產品可以放入的數量。
從大到小遍歷各個產品,找到一個產品,開一個新包裹將其放入。如果剩余位置還可以放產品,那么放入對應產品,改變剩余位置可放產品的數量。直到沒有位置可放或沒有足夠的產品可放為止。再從大到小找下一個產品,開一個新包裹將其放入。重復上述過程,直到看完所有產品為止。
【題解代碼】
解法1:貪心(本人原創)
#include <bits/stdc++.h> using namespace std; int status[8][4];//status[i][j]:包裹中已有1個大小為i*i的產品,此時可以最多放入多少個j*j的產品 void initStatus() {//status[0]:包裹中沒有產品時,各種產品最多可以放多少個 status[2][2] = 8;status[3][2] = 5, status[3][3] = 3;status[4][2] = 5;for(int i = 1; i <= 6; ++i)status[i][1] = 36 - i*i; } int pro[8];//pro[i]:i*i產品的數量 int main() {initStatus(); while(true){int sum = 0, bag = 0, rem[8];//sum:總產品數量 bag:包裹數 rem[i]:當前剩余空間能放幾個i*i for(int i = 1; i <= 6; ++i){cin >> pro[i];sum += pro[i];}if(sum == 0)//如果6個數都是0,那么加和為0,要跳出循環 break;for(int i = 6; i >= 1; --i){while(pro[i] > 0){bag++;//用一個新包裹放i*ipro[i]--;for(int j = 1; j <= 3; ++j)//獲取當前剩余空間情況 rem[j] = status[i][j];int j = 3;while(j >= 1){if(rem[j] > 0 && pro[j] > 0)//如果可以放j*j的產品 {pro[j]--;//放一個產品 if(j == 3){rem[3]--;rem[2] -= 2;rem[1] -= 9;}else if(j == 2){rem[2]--;rem[1] -= 4;}else//j == 1rem[1]--;}else--j;}} }cout << bag << endl;} return 0; }解法2:手動完成貪心過程
思路來自zqhf123博客:zqhf123 1226:裝箱問題
由于箱子種類不多,我們可以手動完成每一步的貪心行為。先裝大產品,看占了多少空間,剩下多少空間。再看小產品。逐次算出當前可以給下一個產品留出的空位。
總結
以上是生活随笔為你收集整理的信息学奥赛一本通 1226:装箱问题 | OpenJudge NOI 4.6 19:装箱问题的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python1乘到10_python写一
- 下一篇: 信息学奥赛一本通 1345:【例4-6】