日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

信息学奥赛一本通 1226:装箱问题 | OpenJudge NOI 4.6 19:装箱问题

發布時間:2025/3/17 编程问答 18 豆豆
生活随笔 收集整理的這篇文章主要介紹了 信息学奥赛一本通 1226:装箱问题 | OpenJudge NOI 4.6 19:装箱问题 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

【題目鏈接】

ybt 1226:裝箱問題
OpenJudge NOI 4.6 19:裝箱問題

【題目考點】

1. 貪心

【解題思路】

該題說是三維立方體,實際上無論是包裹還是產品,高度都是h,因而不用考慮高度,這實際上是二維平面上的問題。

1. 貪心選擇性質的證明

貪心選擇:選擇最大的可以裝入該包裹的產品裝入該包裹

  • 證明:存在最優解包含第一次的貪心選擇。即存在最優解,第一個包裹中包含最大產品。
  • 假設所有最優解都不包含第一次的貪心選擇,即第一個包裹C中不包含最大的產品x。
    最大的產品x一定存在于某個包裹內,記那個包裹為N。我們可以將N中的所有產品和C中的所有產品完全交換。總包裹數量不變,第一個包裹C中存在產品x,這與假設相悖,假設不成立,原命題得證。

  • 證明:前k步都做貪心選擇,存在最優解包含第k+1步的貪心選擇。
  • 是否做貪心選擇區別在于:當前拿到一個最大的可以裝入當前包裹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的產品。
  • 如果C中已經有3個3*3的產品,剩下3*3的位置,這部分位置的產品或空位都可以與x進行交換。
  • 如果C中已經有2個3*3的產品,且剩余的空間中擺了至多3個2*2的產品。
    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產品位置發生變化。
  • 如果C中已經有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產品位置發生變化。
    • x不可能是4*4或更大的產品,如果是,C中可以放x但不放,C中的x只能是0個,而N中的x有1個,這是前面已經討論過的“如果N中x的數量大于C中x的數量”的情況。
      因此N中包括x的部分產品總能和C中的一些產品或空位交換位置。說明第k+1步進行了貪心選擇,選擇了產品x,總包裹數量不變,也是最優解。因而假設不成立,原命題得證。

    2. 具體做法

    考慮各種情況下,剩下的空間最多可以放下幾個各種產品,總結成表格

    已有最多放幾個3*3最多放幾個2*2最多放幾個1*1
    1個6*6000
    1個5*50011
    1個4*40520
    1個3*33527
    2個3*32318
    3個3*3119
    4936

    此這基礎上,每多放一個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:裝箱問題
    由于箱子種類不多,我們可以手動完成每一步的貪心行為。先裝大產品,看占了多少空間,剩下多少空間。再看小產品。逐次算出當前可以給下一個產品留出的空位。

    #include<bits/stdc++.h> using namespace std; int bag;//總包裹數 int k[4] = {0, 5, 3, 1};//k[i]表示3*3的產品有i個時(k[0]表示有4個時)剩余空間可以放2*2產品的個數 int pro[8], p2, p1;//p2:2*2空位數 p1:1*1空位數 int main() { while(true){for(int i = 1; i <= 6; ++i)cin >> pro[i];if(pro[1] == 0 && pro[2] == 0 && pro[3] == 0 && pro[4] == 0 && pro[5] == 0 && pro[6] == 0) break;bag = pro[6] + pro[5] + pro[4] + ceil(pro[3]/4.0);//6*6和5*5和4*4一定是一個占一個箱子,而3*3 4個占一個箱子p2 = 5*pro[4]+k[pro[3]%4];//k[pro[3]%4]:有pro[3]%4個3*3在一個包裹中時,剩下的位置可以放2*2的數目 if(pro[2] > p2)//2*2的個數比我們留出來為2*2的空間個數多,就需要為2*2另開箱子bag += ceil((pro[2]-p2)/9.0);//多出來的2*2箱子應該占用的新箱子數 p1 = 36*bag-36*pro[6]-25*pro[5]-16*pro[4]-9*pro[3]-4*pro[2];//求出當前包裹中所有剩下的可以放1*1的位置數 if(pro[1] > p1)//如果1*1的個數,比我們留出的空間多就需要另開空間 bag += ceil((pro[1]-p1)/36.0);//將多出來的另開箱子 cout << bag << endl;}return 0; }

    總結

    以上是生活随笔為你收集整理的信息学奥赛一本通 1226:装箱问题 | OpenJudge NOI 4.6 19:装箱问题的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。