[蓝桥杯训练] 第八届(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