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,尤其是是第五个测试点,不过答案至少是对了,能拿不少分。
待我更多学习之后再来优化。