📅  最后修改于: 2023-12-03 15:18:04.567000             🧑  作者: Mango
给定平面直角坐标系上 $N$ 个轴平行矩形,其中第 $i$ 个矩形左上角坐标为 $(x_{i1},y_{i1})$,右下角坐标为 $(x_{i2},y_{i2})$,保证 $x_{i1}<x_{i2}$,$y_{i1}<y_{i2}$,且所有矩形两两不重叠。请编写一个程序,计算这些矩形之间缺少顶点的个数。
我们可以将给定的 $N$ 个矩形的所有顶点按照从左到右、从上到下的顺序排序,并用扫描线来统计缺少顶点的个数。
我们先将所有的顶点按照排序规则排序。排序规则是:$x$ 坐标越小的点排在越前面,如果 $x$ 坐标相同,则 $y$ 坐标越小的点排在越前面。
例如,下面的矩形:
(2,6) ________ (7,6)
| |
| |
| |
(2,2) -------- (7,2)
对应的顶点为:
(2,2) (2,6) (7,2) (7,6)
排序结果为:
(2,2) (2,6) (7,2) (7,6)
接下来,我们用一条扫描线从上到下依次扫描所有的顶点。
扫描到一个顶点时,将其加入一个激活边集 $E$(即正在受到扫描线影响的矩形的边)。同时,如果该点是矩形的右上角或者左下角,则该矩形的另一个顶点从激活边集 $E$ 中移除。
每次扫描到一个新的点时,我们需要统计激活边集 $E$ 中所有相邻的线段之间的缺少的顶点个数。
对于相邻的两条线段,如果它们共同包含一个矩形的边,则它们之间没有缺少的顶点。否则,它们之间必然有一个缺少的顶点。
具体的实现方法是,对于激活边集 $E$ 中任意相邻的两条线段 $e_1$ 和 $e_2$,我们判断这两条线段是否分别来自两个不同的矩形。如果是,则它们之间必然有一个缺少的顶点。
需要注意的是,在扫描过程中,我们不能重复计算同一条线段之间的缺少的顶点个数。为了避免重复,我们可以使用一个标记数组 $vis$ 来记录已经计算过的线段。
# -*- coding: UTF-8 -*-
def count_missing_vertices(n, rectangles):
# 将所有顶点排序
points = []
for i in range(n):
x1, y1, x2, y2 = rectangles[i]
points.append((x1, y1))
points.append((x2, y2))
points.append((x1, y2))
points.append((x2, y1))
points.sort()
# 扫描线统计缺少顶点的个数
ans = 0
E = set()
vis = set()
for i in range(len(points)):
x, y = points[i]
for e in E:
if e[0] != x:
u, v = e
if (u, v, x, v) in vis:
continue
vis.add((u, v, x, v))
vis.add((x, v, u, v))
ans += 1
E = {e for e in E if e[1] != y}
for j in range(i + 1, len(points)):
if points[j][1] != y:
break
if y == rectangles[points[j][2] // 4][1] and x != rectangles[points[j][2] // 4][0]:
edges = [(points[j][0], y), (x, points[j][1])]
edges.sort()
E.add((edges[0], edges[1]))
return ans
时间复杂度:$O(N^2 \log N)$
空间复杂度:$O(N)$