第八届蓝桥杯省赛 JavaA组 第十题 标题:油漆面积

题目描述:
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


请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。

所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
不要使用package语句。不要使用jdk1.7及以上版本的特性。
主类的名字必须是:Main,否则按无效代码处理。

虽然这题是A组的题,但是还是比较简单的。

我开始解这题的思路是逐个判断矩形之间的关系,判断他们是相交、外离、内含还是相切,然后将面积逐个求出来,如果是相交则减去相交部分。但是,想了将近3个小时还没能想出三个矩形如果相交该如何求相交部分的面积。后来,参考了下别人写的,我瞬间开窍了。其实没有必要去分析矩形之间的关系。

解题关键是把矩形看作由每个面积为1的点组成的。

1.我们可以定义一个二维数组用来表示所有区域,由题意知,矩形长和宽不超过10000,也就是说所有矩形加起来去除叠加部分面积不会超过10000*10000。在Java中,如果定义一个int二维数组a[10000][10000],知道占的空间是什么概念吗?一个int变量占4个字节,那么这个数组就占到4*10^8 B约等于400MB了,但是题目要求是内存不大于256M哦,所以不能定义为int数组(估计习惯性定义成int的是c/c++程序员吧)。再仔细想一下,其实每个“点”只有包含和不包含两种状态,也就是这个点能被油漆喷到或者不能被喷到。所以数组只要定义为boolean型就可以了,一个boolean变量只占1个字节,这样一来数组占的内存就最多只有100M了。但是,作为Java程序员,一来就把数组长度定死,可不是我的作风啊。其实可以先把输入的所有矩形求出横坐标和纵坐标的最大值,然后再定义数组长度,这样一来,当输入的数据规模不大的时候浪费的空间就少了。

2.依次遍历输入的矩形,并“放入”到定义的所有区域中。

3.遍历所有区域,计算所有“点”的面积

import java.io.BufferedReader;
import java.io.InputStreamReader;

public class Main {

	public static void main(String[] args) throws Exception {
		BufferedReader br = new BufferedReader(
				new InputStreamReader(System.in));
		int n = Integer.parseInt(br.readLine());
		
		// 储存每个矩形的坐标
		int[][] shape = new int[n][4];
		for (int i = 0; i < n; i++) {
			String[] nums = br.readLine().split(" +");
			//下标0为x1,1为y1,2为x2,3为y2
			for (int j = 0; j < 4; j++) {
				shape[i][j] = Integer.parseInt(nums[j]);
			}
		}

		// 求出矩形中最大的x和y坐标值
		int maxX = 0;
		int maxY = 0;
		for (int i = 0; i < n; i++) {
			if (shape[i][0] > maxX) {
				maxX = shape[i][0];
			}
			if (shape[i][2] > maxX) {
				maxX = shape[i][2];
			}
			
			if (shape[i][1] > maxY) {
				maxY = shape[i][1];
			}
			if (shape[i][3] > maxY) {
				maxY = shape[i][3];
			}
		}

		// 创建一个数组表示所有区域,同时也是为了记录是否访问过
		boolean[][] visited = new boolean[maxX + 1][maxY + 1];

		//依次把矩形放入所有区域
		for (int i = 0; i < n; i++) {
			place(i, shape, visited);
		}

		int area = 0;
		//遍历所有区域,计算面积
		for (int i = 0; i < visited.length; i++) {
			for (int j = 0; j < visited[i].length; j++) {
				if (visited[i][j]) {
					area++;
				}
			}
		}

		System.out.println(area);
	}

	/**
	 * 将矩形点放入所有区域中
	 * 
	 * @param i
	 * @param shape
	 * @param visited
	 */
	private static void place(int i, int[][] shape, boolean[][] visited) {
		// 确保x1,y1分别比x2,y2小
		if (shape[i][0] > shape[i][2]) {
			int temp1 = shape[i][0];
			shape[i][0] = shape[i][2];
			shape[i][2] = temp1;
		}
		
		if (shape[i][1] > shape[i][3]) {
			int temp2 = shape[i][1];
			shape[i][1] = shape[i][3];
			shape[i][3] = temp2;
		}

		for (int x = shape[i][0]; x < shape[i][2]; x++) {
			for (int y = shape[i][1]; y < shape[i][3]; y++) {
//				if (!visited[x][y]) {//这里没有必要做判断,做了判断消耗的时间反而更多
					visited[x][y] = true;
//				}
			}
		}

	}

}

蓝桥杯练习系统测试结果


第一个测试数据的输入是

20
29 48 93 107
59 62 87 97
87 94 84 94
35 49 5 18
96 107 57 58
95 98 42 44
46 55 44 51
71 75 63 80
13 24 27 43
61 69 44 51
39 40 46 47
41 48 99 115
55 63 28 37
94 105 97 112
40 52 91 94
93 106 45 49
36 54 35 36
39 52 81 92
44 47 14 26

75 89 5 8

输出是

3796

通过调试可以看出以上输入的20个矩形中,最大的面积是(99-41)*(115-48)=3886,单单一个矩形面积就比答案给出的大了,然后其它测试数据都是正确的,所以可以断定这个测试答案有误。

阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页