📜  门|门CS 2012 |问题 1(1)

📅  最后修改于: 2023-12-03 15:28:49.081000             🧑  作者: Mango

门|门CS 2012 |问题 1

这道题目是一个经典的计算几何问题,需要编写程序求出两个凸多边形的交。

题目描述

有两个凸多边形 $A$ 和 $B$,请编写程序计算出它们的交的面积。

输入格式:

第一行为一个整数 $n$,表示 $A$ 的顶点数。接下来 $n$ 行,每行两个整数 $x$ 和 $y$,表示 $A$ 的一个顶点的坐标。

接下来一行为一个整数 $m$,表示 $B$ 的顶点数。接下来 $m$ 行,每行两个整数 $x$ 和 $y$,表示 $B$ 的一个顶点的坐标。

输出格式:

一个实数,表示两个凸多边形的交的面积。保留两位小数。

解题思路

由于题目要求求出两个凸多边形的交的面积,因此可以先将两个凸多边形分别进行逆时针旋转,使其各自顶点按顺序存储。接着,分别对两个凸多边形进行求交操作,最后再将得到的交的面积相加,即可得到两个凸多边形的交的面积。

通过求每个多边形的凸包,可以得到该多边形的各个顶点按逆时针顺序的排列方式。由于凸包的时间复杂度为 $O(n\log n)$,因此整个求解的时间复杂度为 $O(n\log n)$。

参考代码
# -*- coding:utf-8 -*-

from typing import List, Tuple

def convex_hull(points: List[Tuple[int, int]]) -> List[Tuple[int, int]]:
    """
    求点集的凸包,返回凸包上所有点的坐标(按逆时针顺序)。
    """
    def cross(p1, p2, p3):
        """
        计算向量p1p2和向量p2p3的叉积。
        """
        x1, y1 = p1
        x2, y2 = p2
        x3, y3 = p3
        return (x2 - x1) * (y3 - y2) - (y2 - y1) * (x3 - x2)

    if len(points) <= 3:
        return points

    points.sort()  # 找到最左边的点,作为已知点
    pivot = points[0]  

    points = sorted(points[1:], key=lambda x: -cross(pivot, pivot, x))  # 将点按极角排序

    hull = [pivot, points[0]]
    for p in points[1:]:
        while len(hull) > 1 and cross(hull[-2], hull[-1], p) < 0:
            hull.pop()
        hull.append(p)

    return hull

def intersection_area(A: List[Tuple[int, int]], B: List[Tuple[int, int]]) -> float:
    """
    求凸多边形A与凸多边形B的交的面积.
    """
    PA = convex_hull(A)
    PB = convex_hull(B)

    PA.append(PA[0])
    PB.append(PB[0])

    area = 0
    for i in range(len(PA) - 1):
        for j in range(len(PB) - 1):
            if cross(PA[i], PB[j], PA[i + 1]) * cross(PA[i], PB[j + 1], PA[i + 1]) < 0 and \
                cross(PB[j], PA[i], PB[j + 1]) * cross(PB[j], PA[i + 1], PB[j + 1]) < 0:
                area += polygon_intersect_area(PA[i], PA[i + 1], PB[j], PB[j + 1])

    return area

def polygon_intersect_area(p1: Tuple[int, int], p2: Tuple[int, int], q1: Tuple[int, int], q2: Tuple[int, int]) -> float:
    """
    计算线段p1-p2和线段q1-q2的交的面积.
    """
    def area(p1, p2, p3):
        """
        计算由p1p2和p1p3组成的三角形的面积.
        """
        x1, y1 = p1
        x2, y2 = p2
        x3, y3 = p3
        return (x2 - x1) * (y3 - y1) - (y2 - y1) * (x3 - x1)

    area_p1p2q1 = area(p1, p2, q1)
    area_p1p2q2 = area(p1, p2, q2)
    area_q1q2p1 = area(q1, q2, p1)
    area_q1q2p2 = area(q1, q2, p2)

    if (area_p1p2q1 * area_p1p2q2 < 0) and (area_q1q2p1 * area_q1q2p2 < 0):
        return abs(area(p1, p2, q1) + area(p1, p2, q2) + area(q1, q2, p1) + area(q1, q2, p2)) / 2.0
    else:
        return 0

if __name__ == '__main__':
    n = int(input())
    A = [tuple(map(int, input().split())) for _ in range(n)]
    m = int(input())
    B = [tuple(map(int, input().split())) for _ in range(m)]

    print("{:.2f}".format(intersection_area(A, B)))

上面的代码实现了两个凸多边形的求交面积操作。其中,convex_hull函数用于求一个点集的凸包;polygon_intersect_area函数用于求线段之间的交的面积;intersection_area函数用于求两个凸多边形的交的面积。