题解 #9037 Ancient Maps, Hidden Danger

· · 算法·理论

Ancient Maps, Hidden Danger

给出 m\,(m\leq 30) 个不交简单多边形(总点数 n\leq 90),从无限远的所有方向打光,求出多边形遮挡的阴影面积。

记录一下怎么完成这个毒瘤题的。阴影面积不好算,考虑算被照亮的面积,如果点 P 能被照亮,那么可以稍微把光线旋转一些,使得照亮 P 的光线恰好经过一个多边形的顶点 A。于是可以把 P 当成是 A 照亮的。

思考点 P 被点 A 照亮的充分条件,需要满足

枚举每个顶点 A 计算它能够照亮的区域。根据上面的两个条件,把所有的顶点及其关于 A 的对称点A 为原点做极角排序,每个极角区间一定是极小的——要么全被照亮要么全部无法被照亮。

接下来计算一个极角区间能够被照亮多少,假设这个区间的两个向量是 \overrightarrow{AB}\overrightarrow{AC}。先判断射线 \overrightarrow{AB^\prime}\overrightarrow{AC^\prime} 是否在多边形外,可以在射线方向上选择一个略微超出值域范围的点,然后用判断线段在多边形外的方法进行判断。

如果反向射线没有相交,那么找到与 \overrightarrow{AB},\overrightarrow{AC} 相交的一条边,设交点分别为 E,F,判断 \overline{AE}\overline{AF} 是否在多边形外。两条射线会相交在同一条边上,如果没有交可以跳过这个区间,说明这个区域会被其他点照亮。若能够找到(唯一)一对符合条件的 E,F,那么 \triangle AEF 就是一个会被 A 照亮的区域。

以多边形的每个顶点为原点,能够找出 \mathcal{O}(n^2) 个被照亮的三角形。将这些三角形取并集就是所有被照亮的区域,然后用全集 - 多边形面积 - 照亮区域就是答案。这里的全集是所有点形成的凸包的面积,因为在上面的算法中每条光线都是由两个整点确定的,那么外侧的边就是凸包的边。

然后就是一些 corner case,大概有这些:

时间复杂度瓶颈在于求面积并,由于有 \mathcal{O}(n^2) 个三角形,因此时间复杂度为 \mathcal{O}(n^4\log n)。官解给出的面积并的做法是:对所有线段交点建平面图然后单独计算每个 Cell 的面积,不需要每次都排序因此十分高效;实际上常规扫描线做法的效率也比较可观,可以在 ~3000ms 的时间通过。

提交记录