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

介绍了一种计算多个矩形覆盖总面积的方法,通过定义一个二维boolean数组来标记被覆盖的点,最终统计被覆盖的点数得出总面积。
题目描述:
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,单单一个矩形面积就比答案给出的大了,然后其它测试数据都是正确的,所以可以断定这个测试答案有误。

### 关于第四届蓝桥杯 Java A目及解答 目前提供的引用中并未直接提及第四届蓝桥杯 Java A的具体目及其解答。然而,可以通过分析其他届次的相关目来推测可能涉及的内容以及解方法。 #### 蓝桥杯特点 蓝桥杯通常会考察选手的基础编程能力、算法设计能力和逻辑思维能力。Java A作为最高难度级别之一,其目往往涵盖了较复杂的算法和数据结构应用。以下是基于往届比总结的一些常见考点: 1. **基础算法** 基础算法包括但不限于贪心法、动态规划、回溯法(DFS/BFS)、分治法等。例如,在某些目中可能会要求实现深度优先搜索(DFS)或广度优先搜索(BFS),用于解决路径寻找或者状态空间探索等问[^1]。 2. **字符串处理** 字符串操作也是常见的考查点之一。这不仅限于简单的字符匹配,还可能涉及到正则表达式、模式识别甚至压缩编码等内容。比如有一道关于反转二进制位的目就属于此类范畴[^3]。 3. **数学建模与计算几何** 数学问是历年来的重要成部分,有时需要运用到合数论、概率统计等方面的知识;另外还有部分试聚焦于平面图形的操作——如判断线段相交与否、求多边形面积等等[^2]。 4. **优化技巧** 对于大规模输入的数据集来说,如何提高程序运行效率显得尤为重要。这就意味着参者不仅要写出功能正确的代码,还需要考虑时间复杂度和空间复杂度之间的平衡关系。如果单纯依赖暴力枚举,则很可能因为超出规定时限而丢掉分数。 --- #### 解决方案框架建议 针对上述提到的各种类型的问,这里给出一些通用性的解决方案框架供参考: - 如果遇到排列合类问,可以尝试采用递归函数配合剪枝策略减少不必要的分支运算; - 当面临图遍历时,应明确区分连通性和可达性概念,并合理选用队列(适用于层序访问)还是栈(适合深入挖掘); - 处理数值型挑战时,除了常规算术外还要注意边界条件设定以及溢出防护; - 设计模拟场景下的交互流程前先梳理清楚各个阶段的状态转移规律. 下面展示一段伪代码表示如何通过递归来完成全排列生成任务: ```java public class Permutation { public static void permute(int[] nums, int start){ if(start == nums.length -1 ){ System.out.println(Arrays.toString(nums)); }else{ for(int i=start;i<nums.length;i++){ swap(nums,start,i); //交换位置 permute(nums,start+1); //继续向下一层迭代 swap(nums,start,i); //恢复原状以便下一轮循环使用 } } } private static void swap(int []arr,int a ,int b){ int temp=arr[a]; arr[a]=arr[b]; arr[b]=temp; } } ``` 此段代码展示了基本的递归思想应用于数元素重新排序的过程当中. --- ###
评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值