蓝桥杯油漆面积

题目描述

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

java代码1

直接用true覆盖所有的矩形,最后从矩形中求得所有覆盖的面积。
注意不能用int类型,内存会超。
这是典型的“计算思维“,其实就是暴力法求解。

import java.util.*;

public class Main {
	static int N;
	static boolean[][] p = new boolean[10001][10001];
	static int ans = 0;

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		N = sc.nextInt();
		int x1 = 0, x2 = 0, y1 = 0, y2 = 0;
		for (int i = 0; i < N; i++) {
			x1 = sc.nextInt();
			y1 = sc.nextInt();
			x2 = sc.nextInt();
			y2 = sc.nextInt();

			paint(x1, y1, x2, y2);
		}
		// 遍历矩阵计算面积
		for (int i = 0; i < p.length; i++) {
			for (int j = 0; j < p[i].length; j++) {
				if (p[i][j]) {
					ans++;
				}
			}
		}
		System.out.println(ans);
		sc.close();
	}

	// 覆盖该矩形内的点
	private static void paint(int x1, int y1, int x2, int y2) {
		for (int i = x1; i < x2; i++) {
			for (int j = y1; j < y2; j++) {
				p[i][j] = true;
			}
		}
	}

}

java代码2

线段树+扫描线+离散化
该代码转载自
https://blog.csdn.net/weixin_41793113/article/details/88422169?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-3.channel_param&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-3.channel_param
大体思路是将输入的数据做一个点数组和矩形横线边数组,将这两个数组排序,将点数组去重,构造线段树维护cnt,然后遍历扫描线,在遍历过程中计算,直至最终得到ans。

import java.util.Arrays;
import java.util.Scanner;

public class Main {

	/* 辅助的数据结构:扫描线 */
	private static class Line implements Comparable<Line> {
		int x1, x2, h, f;// 左右坐标,纵坐标(高度),f=1为入边,f=-1为出边

		Line(int _l, int _r, int _h, int _f) {
			x1 = _l;
			x2 = _r;
			h = _h;
			f = _f;
		}

		/* 按高度排序 */
		@Override
		public int compareTo(Line o) {
			if (h < o.h)
				return -1;
			else if (h > o.h)
				return 1;
			else
				return 0;
		}
	}

	/* 线段树的定义 */
	private static class SegTree {
		int pl, pr, cnt, len;// 左端点编号,右端点编号,被覆盖次数,两个端点之间被覆盖的长度

		SegTree() {
		}

		SegTree lson, rson;
	}

	static int n;
	static int[] X;// = new int[N << 1];//记录所有的横坐标
	// int PL=0,PR;
	static Line[] lines;// = new Line[N];

	/* 构建区间树 */
	static SegTree buildTree(int pl, int pr) {
		SegTree t = new SegTree();
		t.pl = pl;
		t.pr = pr;
		if (pl == pr)
			return t;
		int mid = ((pl + pr) >> 1);
		t.lson = buildTree(pl, mid);
		t.rson = buildTree(mid + 1, pr);
		return t;
	}

	static void updateLength(SegTree pTree, int tl, int tr) {
		if (pTree.cnt > 0) {
			pTree.len = X[tr] - X[tl - 1];// 将区间树上的端点(序号)反入到X中求得二维坐标上的实际横坐标
		} else if (tl == tr) {
			pTree.len = 0;
		} else {// 负数
			pTree.len = pTree.lson.len + pTree.rson.len;
		}

	}

	static void update(SegTree tree, int pl, int pr, int value) {
		int tl = tree.pl;
		int tr = tree.pr;
		if (pl <= tl && pr >= tr) {
			tree.cnt += value;
			updateLength(tree, tl, tr);
			return;
		}
		int m = (tl + tr) >> 1;
		if (pl <= m)
			update(tree.lson, pl, pr, value);
		if (pr > m)
			update(tree.rson, pl, pr, value);
		updateLength(tree, tl, tr);
	}

	static int ans;

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		n = sc.nextInt();
		X = new int[n * 2];
		lines = new Line[n * 2];
		int x1, y1, x2, y2;
		int index = 0;
		for (int i = 0; i < n; i++) {
			x1 = sc.nextInt();
			y1 = sc.nextInt();
			x2 = sc.nextInt();
			y2 = sc.nextInt();
			X[index] = x1;
			lines[index] = new Line(x1, x2, y1, 1);// 高度1
			index++;

			X[index] = x2;
			lines[index] = new Line(x1, x2, y2, -1);// 高度2
			index++;
		}
		// 大体上就有了2n个横坐标,2n条水平线段
		Arrays.sort(X);// 所有横坐标点排序
		Arrays.sort(lines);// 扫描线排序,从低到高
		/* 离散化横坐标 */
		int X_end = unique(X);// 去重返回值是一个迭代器,它指向的是去重后容器中不重复序列的最后一个元素
		// PR=X_end;
		// 初始化线段树
		SegTree root = buildTree(1, X_end);
		// 从低到高,遍历扫描线
		for (int i = 0; i < index - 1; ++i) {
			int pl = Arrays.binarySearch(X, 0, X_end + 1, lines[i].x1);// 二分查找,记录下标,代表是第几个点
			int pr = Arrays.binarySearch(X, 0, X_end + 1, lines[i].x2);// 二分查找,记录下标,代表是第几个点
			update(root, pl + 1, pr, lines[i].f);
			ans += root.len * (lines[i + 1].h - lines[i].h);// 宽度*高度

		}
		System.out.println(ans);
	}

	private static int unique(int[] x) {
		int index = 0;
		for (int i = 1; i < x.length; i++) {
			if (x[i] == x[index])
				continue;
			else {
				index++;
				x[index] = x[i];
			}
		}
		return index;
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值