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. 運行結果








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