[藍橋杯訓練] 第八屆(2017)省賽 C/C++ A組 T10 - 油漆面積


1. 題目

X星球的一批考古機器人正在一片廢墟上考古。
該區域的地面堅硬如石、平整如鏡。
管理人員為方便,建立了標准的直角坐標系。

每個機器人都各有特長、身懷絕技。它們感興趣的內容也不相同。
經過各種測量,每個機器人都會報告一個或多個矩形區域,作為優先考古的區域。

矩形的表示格式為(x1,y1,x2,y2),代表矩形的兩個對角點坐標。

為了醒目,總部要求對所有機器人選中的矩形區域塗黃色油漆。
小明並不需要當油漆工,只是他需要計算一下,一共要耗費多少油漆。

其實這也不難,只要算出所有矩形覆蓋的區域一共有多大面積就可以了。
注意,各個矩形間可能重疊。

本題的輸入為若干矩形,要求輸出其覆蓋的總面積。

輸入格式:
第一行,一個整數n,表示有多少個矩形(1<=n<10000)
接下來的n行,每行有4個整數x1 y1 x2 y2,空格分開,表示矩形的兩個對角頂點坐標。
(0<= x1,y1,x2,y2 <=10000)

輸出格式:
一行一個整數,表示矩形覆蓋的總面積面積。

例如,
輸入:
3
1 5 10 10
3 1 20 20
2 7 15 17

程序應該輸出:
340

再例如,
輸入:
3
5 2 10 6
2 7 12 10
8 1 15 15

程序應該輸出:
128

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


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

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

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

 

2. 分析

2.1 如何計算面積

  因為坐標全是整數,這樣就可以用比較簡單的方法--記錄坐標

  但是會有TLE的問題,請自行取舍。

  以下是一個簡單的圖例:

  

  給出了x和y這兩個對角的坐標,由於全是整數(離散),我們可以直接用兩個for循環來計算面積。

2.2 輸入坐標的兩種可能

  對角有兩種情況,我們若想使用坐標法求面積,必須統一從左下角往右上角遍歷,因此需要把兩種類型的對角統一變成左下-右上形式的。方法如下:

 

2.3 如何解決重疊問題

  我的想法是比較簡單的:建立一個10000*10000的bool型二維數組,對於每次輸入的坐標,將對應區域內的bool設為true,最后厲遍統計true的數量就是面積。

void Print(int x1, int y1, int x2, int y2, bool plain[][10001]) { //第一種方法
    int xBegin = min(x1,x2); //這是左下角的x int yBegin = min(y1,y2); //這是左下角的y int xEnd = max(x1,x2);  //這是右上角的x int yEnd = max(y1,y2); //這是右上角的y for (int i=xBegin; i<xEnd; i++) { for (int j=yBegin; j<yEnd; j++) { plain[i][j] = true;//暴力置位 } } }

  無腦暴力,最為致命。這樣做的好處是:你根本不用考慮重復的問題,因為同一個位置設置多少次也不會有任何改變,可以放心使用。當然,必須要注意的是,10000*10000的數組是會爆棧的,必須用new分配堆內存給該變量。

  或者你也可以使用STL里面的set:構造一個字符串,格式為xxx-yyy,其中xxx為x坐標,yyy為y坐標,之后將其插入集合中,由於同樣的坐標具有一樣的形式,無法重復插入,最后只需要輸出set.size()就能得到答案。(該方法不容易爆,推薦使用)  

void Print(int x1, int y1, int x2, int y2, set<string> &st) { //第二種方法,注意&不要漏了
    int xBegin = min(x1,x2); int yBegin = min(y1,y2); int xEnd = max(x1,x2); int yEnd = max(y1,y2); for (int i=xBegin; i<xEnd; i++) { for (int j=yBegin; j<yEnd; j++) { ostringstream s; string str; s.clear(); s << i; str += s.str(); str += '-'; s.clear(); s << j; str += s.str(); st.insert(str); } } }

 

3. 代碼

 1 #include <iostream>
 2 #include <sstream>
 3 #include <fstream>
 4 #include <algorithm>
 5 #include <vector>
 6 #include <set>
 7 #include <list>
 8 #include <string>
 9 #include <map>
10 #include <cmath>
11 #include <cstring>
12 #include <cstdlib>
13 #include <windows.h>
14 
15 using namespace std;
16 
17 
18 void Print(int x1, int y1, int x2, int y2, set<string> &st); 19 #define DEBUG 1  //當你使用官方的txt測試數據時,可以將該宏置位,並在第27行更改文件名,這樣就可以從txt讀入測試數據,最后自行對照對應的out.txt 20 21 22 int main() { 23 set<string> st; 24 int n,x1,y1,x2,y2,count; 25 long time = GetTickCount(); 26 #if DEBUG 27 ifstream fin( "in1.txt" ,ios::in); 28 fin >> n; 29 for (int i=0; i<n; i++) { 30 fin >> x1 >> y1 >> x2 >> y2; 31  Print(x1,y1,x2,y2,st); 32 count = st.size(); 33  } 34 #else 35 cin >> n; 36 for (int i=0; i<n; i++) { 37 cin >> x1 >> y1 >> x2 >> y2; 38  Print(x1,y1,x2,y2,st); 39 count = st.size(); 40  } 41 #endif 42 time = GetTickCount() - time;  //計算時間 43 cout << st.size() << endl <<"time:" << time << " ms" << endl; 44 return 0; 45 } 46 47 void Print(int x1, int y1, int x2, int y2, set<string> &st) { 48 int xBegin = min(x1,x2); 49 int yBegin = min(y1,y2); 50 int xEnd = max(x1,x2); 51 int yEnd = max(y1,y2); 52 for (int i=xBegin; i<xEnd; i++) { 53 for (int j=yBegin; j<yEnd; j++) { 54  ostringstream s; 55 string str; 56 57  s.clear(); 58 s << i; 59 str += s.str(); 60 str += '-'; 61  s.clear(); 62 s << j; 63 str += s.str(); 64  st.insert(str); 65  } 66  } 67 }

 

 

4. 運行結果

 

最后兩個嚴重TLE,尤其是是第五個測試點,不過答案至少是對了,能拿不少分。

待我更多學習之后再來優化。


免責聲明!

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



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