蓝桥杯油漆面积

    科技2022-07-10  111

    题目描述

    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; } }
    Processed: 0.031, SQL: 8