过度种植
过度种植
农夫约翰购买了一台新机器,该机器能够在其农场的任何“轴向对齐”(即具有垂直和水平边)的矩形区域内种草。
不幸的是,这台机器有一天出了故障,并在 $N$ 个不同的矩形区域内进行了种草工作,其中一些区域可能会有重叠。
给定机器工作的具体 $N$ 个矩形区域,请你计算种上草的区域的总面积是多少。
输入格式
第一行包含整数 $N$。
接下来 $N$ 行,每行包含四个整数 $x_{1},y_{1},x_{2},y_{2}$,表示其中一个矩形区域的左上角坐标 $\left( {x_{1},y_{1}} \right)$ 和右下角坐标 $\left( {x_{2},y_{2}} \right)$。
输出格式
输出种上草的区域的总面积。
数据范围
$1 \leq N \leq 10$,
$−10000 \leq x_{1},y_{1},x_{2},y_{2} \leq 10000$,
$x_{1} < x_{2}$,
$y_{1} > y_{2}$。
输入样例:
2 0 5 4 1 2 4 6 2
输出样例:
20
解题思路
如果$N$比较大的话,例如$N = 1000$,就需要用到扫描线。如果$N = 10000$还需要用到线段树来优化。但这里的$N$最大为$10$,并不需要用到那么复杂的写法。容易发现这些矩形的并集是一个不规则的图形,比较难求,但这些矩形的交集也是矩形,就比较好求了。因此我们发现并集不好求而交集好求,就可以用到容斥原理。容斥原理的公式如下:$$\left| \bigcup\limits_{1 \leq i \leq n} {S_{i}} \right| = \sum\limits_{1 \leq i \leq n} {\left| S_{i} \right|} - \sum\limits_{1 \leq {i<j} \leq n} {\left| S_{i} \cap S_{j} \right|} + \sum\limits_{1 \leq {i<j<k} \leq n} {\left| S_{i} \cap S_{j} \cap S_{k} \right|} - \dots + {\left( -1 \right)}^{n-1}\left| \bigcap\limits_{1 \leq i \leq n} {S_{i}} \right|$$
这样就可以把求并集的问题转换为求交集的问题。虽然交集好求,但项数很多,一共有$C_{n}^{1} + C_{n}^{2} + \dots + C_{n}^{n} = 2^{n} - 1$项,由于$N$最大只有$10$,因此最多也就只有$1023$项,再加上求所有矩形的交集,因此时间复杂度为$O \left( 2^{n} \times n \right)$。
矩形求交集其实就是区间求交,我们把$X$轴和$Y$轴独立开来看,例如$X$轴上有两个区间$\left[ {a,b} \right]$和$\left[ {c,d} \right]$,那么这两个区间的交集就是$\left[ {max \{{a,c}\},~ min \{{b,d}\}} \right]$。同理$Y$轴的区间求交也是如此。
我们在枚举每次求交集的矩形个数的时候(也就是枚举$C_{n}^{i}$),可以用二进制枚举。同时读入的坐标是数学坐标系,$y_{1} > y_{2}$,为了让$y_{1} < y_{2}$与$x_{1} < x_{2}$保持一致方便区间求交,我们把坐标系变成矩阵坐标系,即把左上角的点和右下角的点转化成左下角的点和右上角的点。
AC代码如下:
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 const int N = 15, INF = 0x3f3f3f3f; 5 6 int n; 7 struct Node { 8 int x1, y1, x2, y2; 9 }p[N]; 10 11 int get(int st) { 12 // 初始定义一个无穷大的矩形 13 int x1 = -INF, y1 = -INF, x2 = INF, y2 = INF, cnt = 0; 14 for (int i = 0; i < n; i++) { 15 if (st >> i & 1) { 16 cnt++; // 求交矩阵个数+1 17 18 // x轴上求交 19 x1 = max(x1, p[i].x1); 20 x2 = min(x2, p[i].x2); 21 22 // y轴上求交 23 y1 = max(y1, p[i].y1); 24 y2 = min(y2, p[i].y2); 25 } 26 } 27 28 int ret = max(x2 - x1, 0) * max(y2 - y1, 0); // 有可能没有交集,算出是负数,因此要与0取最大值 29 if (cnt % 2 == 0) ret *= -1; // 如果矩形的个数为偶数,根据公式要返回负数值 30 31 return ret; 32 } 33 34 int main() { 35 scanf("%d", &n); 36 for (int i = 0; i < n; i++) { 37 scanf("%d %d %d %d", &p[i].x1, &p[i].y2, &p[i].x2, &p[i].y1); // y1 < y2 38 } 39 40 int ret = 0; 41 for (int i = 1; i < 1 << n; i++) { 42 ret += get(i); // 获取i状态下(i的二进制有多少个1)的矩形求交的面积 43 } 44 printf("%d", ret); 45 46 return 0; 47 }
补充个扫描线加线段树的做法。AC代码如下,时间复杂度为$O(n \times \log{M})$:
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 const int N = 30, M = 2e4 + 10; 5 6 struct Seg { 7 int x, y1, y2, c; 8 }seg[N]; 9 struct Node { 10 int l, r, cnt, len; 11 }tr[M * 4]; 12 13 void build(int u, int l, int r) { 14 if (l == r) { 15 tr[u] = {l, r, 0, 0}; 16 } 17 else { 18 int mid = l + r >> 1; 19 build(u << 1, l, mid); 20 build(u << 1 | 1, mid + 1, r); 21 tr[u] = {l, r, 0, 0}; 22 } 23 } 24 25 void pushup(int u) { 26 if (tr[u].cnt) tr[u].len = tr[u].r + 1 - tr[u].l; 27 else if (tr[u].l == tr[u].r) tr[u].len = 0; 28 else tr[u].len = tr[u << 1].len + tr[u << 1 | 1].len; 29 } 30 31 void modify(int u, int l, int r, int c) { 32 if (tr[u].l >= l && tr[u].r <= r) { 33 tr[u].cnt += c; 34 pushup(u); 35 } 36 else { 37 int mid = tr[u].l + tr[u].r >> 1; 38 if (l <= mid) modify(u << 1, l, r, c); 39 if (r >= mid + 1) modify(u << 1 | 1, l, r, c); 40 pushup(u); 41 } 42 } 43 44 int main() { 45 int n; 46 scanf("%d", &n); 47 for (int i = 0, j = 0; i < n; i++) { 48 int x1, y1, x2, y2; 49 scanf("%d %d %d %d", &x1, &y1, &x2, &y2); 50 seg[j++] = {x1, y2, y1, 1}; 51 seg[j++] = {x2, y2, y1, -1}; 52 } 53 sort(seg, seg + n + n, [&](Seg &a, Seg &b) { 54 return a.x < b.x; 55 }); 56 build(1, -1e4, 1e4); 57 int ret = 0; 58 modify(1, seg[0].y1, seg[0].y2 - 1, seg[0].c); 59 for (int i = 1; i < n + n; i++) { 60 ret += tr[1].len * (seg[i].x - seg[i - 1].x); 61 modify(1, seg[i].y1, seg[i].y2 - 1, seg[i].c); 62 } 63 printf("%d", ret); 64 65 return 0; 66 }
参考资料
AcWing 2032. 过度种植(春季每日一题2022):https://www.acwing.com/video/3878/
本文来自博客园,作者:onlyblues,转载请注明原文链接:https://www.cnblogs.com/onlyblues/p/16300121.html