[藍橋杯訓練] 第八屆(2017)省賽 C/C++ A組 T09 - 分巧克力


1. 題目

標題: 分巧克力

兒童節那天有K位小朋友到小明家做客。小明拿出了珍藏的巧克力招待小朋友們。
小明一共有N塊巧克力,其中第i塊是Hi x Wi的方格組成的長方形。

為了公平起見,小明需要從這 N 塊巧克力中切出K塊巧克力分給小朋友們。切出的巧克力需要滿足:

1. 形狀是正方形,邊長是整數
2. 大小相同

例如一塊6x5的巧克力可以切出6塊2x2的巧克力或者2塊3x3的巧克力。

當然小朋友們都希望得到的巧克力盡可能大,你能幫小Hi計算出最大的邊長是多少么?

輸入
第一行包含兩個整數N和K。(1 <= N, K <= 100000)
以下N行每行包含兩個整數Hi和Wi。(1 <= Hi, Wi <= 100000)
輸入保證每位小朋友至少能獲得一塊1x1的巧克力。

輸出
輸出切出的正方形巧克力最大可能的邊長。

樣例輸入:
2 10
6 5
5 6

樣例輸出:
2

資源約定:
峰值內存消耗(含虛擬機) < 256M
CPU消耗 < 1000ms


請嚴格按要求輸出,不要畫蛇添足地打印類似:“請您輸入...” 的多余內容。

注意:
main函數需要返回0;
只使用ANSI C/ANSI C++ 標准;
不要調用依賴於編譯環境或操作系統的特殊函數。
所有依賴的函數必須明確地在源文件中 #include <xxx>
不能通過工程設置而省略常用頭文件。

提交程序時,注意選擇所期望的語言類型和編譯器類型。

2. 分析

2.1 如何理解題意

一個x*y的巧克力能分多少塊正方形出來,這其實是很簡單的問題。我們很容易發現:

①對於一個矩形,能分離的最大的正方形的變長取決於該矩形最小的邊長。

②在①的基礎上,縮小邊長能分出更多的巧克力,但他們拼起來肯定不會超過最大的那個正方形。

我們還是用圖來解釋,假設有一個2*3的巧克力:

那么能分出最大的巧克力顯然是2*2,也就是2*3中最短邊“2”作為邊長的正方形,再往下分,1*1的巧克力顯然是基於原本最大的2*2正方形分割而來的。

進而,我們能很容易的發現,對任意x*y的巧克力,能夠分出邊長為i的正方形的小巧克力的數量為:(x/i)*(y/i),這里利用整型除法向下取整的特性。舉個例子,5*6的巧克力,當i=2時,一共能分出(5/2)*(6/2)=2*3=6塊巧克力;i=3時,一共能分出(5/3)*(6/3)=1*2=2塊巧克力。

2.2 怎么選取最大的巧克力邊長

輸入n組數據,每組有兩個邊長,那么根據我們上面的結論,只需要做一個for循環,並使i從1至maxShortSide,其中maxShortSide就是在n組數據中最大的短邊。

那么,我們只需對每一個i,分別對n組數據(巧克力)計算可以分出的總數量並相加,若大於k則符合要求並記錄,然后再使i++,若此時不能滿足總數大於k,則上一個i就是能分出來的最大邊長的巧克力。這里注意的是,只要總數大於k就可以停止相加,即使程序還未遍歷n組數據。這樣的設計可以優化時間量度,避免TLE。

3. 程序

 1 #include <iostream>
 2 #include <sstream>
 3 #include <algorithm>
 4 #include <vector>
 5 #include <set>
 6 #include <list>
 7 #include <string>
 8 #include <map>
 9 #include <cmath>
10 #include <cstring>
11 #include <cstdlib>
12 #include <fstream>
13 using namespace std;
14 
15 #define DEBUG 1  //DEBUG為1,則需要在第23行更改輸入的文件名
16 
17 
18 int main() {
19     set<string> st;
20     long n, k;
21     long currentMax=0, maxShortSide=0;   //int類型也行,看題目的規模 22 #if DEBUG
23     ifstream fin( "in7.txt" ,ios::in);
24     fin >> n >> k;
25 #else    
26     cin >> n >> k;
27 #endif
28     long chocolate[n][2];  
29     for (int i=0; i<n; i++) {
30 #if DEBUG
31         fin >> chocolate[i][0] >> chocolate[i][1];  //從文件導入測試數據 32 #else
33         cin >> chocolate[i][0] >> chocolate[i][1];  //控制台輸入數據 34 #endif        
35         if (maxShortSide < min(chocolate[i][0],chocolate[i][1])) {
36             maxShortSide = min(chocolate[i][0],chocolate[i][1]);  //尋找maxShortSide的值 37         }
38     }
39     for (long i=1; i<=maxShortSide; i++) {
40         int sum = 0;
41         for (long j=0; j<n; j++) {
42             sum+= (chocolate[j][0]/i) * (chocolate[j][1]/i); //求出本塊巧克力能被分解成多少塊邊長為i的正方形小巧克力,並於前面的數量相加 43             if (sum >= k) break;  //若相加后大於小朋友的數量k,則直接退出循環,因為數量已經滿足題目需求 44         }
45         if (sum >= k && i > currentMax) { //當總數大於小朋友數量且新的i比舊的cunrrentMax還要大,則更新currentMax 46             currentMax = i;
47         }
48         else if (sum < k) {   //另一處優化,節省時間,當某個i值無法滿足k的要求時,大於i的值自然也無法滿足,直接break 49             break;
50         }
51     }
52     cout << currentMax;  //輸出結果 53     return 0;
54 }

 

4. 運行結果

時間明顯少於限制時間,故未記錄運行時間


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM