📜  门|门 IT 2008 |第 63 题(1)

📅  最后修改于: 2023-12-03 14:58:36.467000             🧑  作者: Mango

题目介绍

本题为门门IT 2008年第63题,是一道计算几何题目。需要完成的任务是求解多边形中心。本题考察了学生的数学和编程能力。

题目描述

假定有一个多边形,其中所有的边都是平行于坐标轴的。现在需要编写一个程序,求出这个多边形的中心坐标。中心是指平面图形中所有点的平均值。比如,三角形的中心就是它的重心。

输入格式

输入文件 poly.in 包含三行内容:

  • 第一行为多边形的顶点个数 N(3 ≤ N ≤ 1000);
  • 第二行为各个顶点的坐标 x1, y1, x2, y2, … , xn, yn,其中 |xi|, |yi| ≤ 100000,且相邻两点都不相同。多边形按顺时针或逆时针的顺序给出。
输出格式

输出文件 poly.out 包含一行两个浮点数,表示多边形的中心坐标。坐标保留两位小数,中间用一个空格隔开。

样例输入

5 0 0 0 3 4 5 6 2 2 1

样例输出

2.20 2.20

编程思路

本题的难点在于如何求出多边形的中心坐标。首先考虑多边形的重心,这是求解多边形中心的一种常见方法。重心是多边形内所有点的平均值,也是多边形各边的中线交点,具体地,设多边形N个顶点的坐标分别为(x1,y1),(x2,y2), ... , (xn,yn),则重心坐标为:

(x_g, y_g) = \left( \frac{\sum_{i=1}^n x_i}{n}, \frac{\sum_{i=1}^n y_i}{n} \right)

其中,xg和yg分别是重心的横坐标和纵坐标。n是多边形的边数。

因此,我们可以先求出多边形各顶点的坐标之和,再除以边数n,即可得到多边形的重心。

然而,本题的难点在于不仅需要求解多边形的重心,还需要求解多边形的中心。中心是指平面图形中所有点的平均值。

对于简单多边形,即所有的偏移图形都没有自交情况的多边形,它的中心坐标与重心坐标是相同的。但是,对于复杂多边形,二者的坐标不一定相同。

因此,本题需要对多边形的重心进行修正,得到正确的多边形中心坐标。具体地,我们需先将多边形按照逆时针顺序排序,并按照原重心朝向选择一个顶点作为起点,再依次连接连续的多边形各个顶点,形成一条射线。将射线绕重心旋转180度并平移原位置,得到一条对称的射线,其终点即为多边形的中心坐标。

代码片段

以下是本题的部分Python代码实现:

def get_polygon_center(n, points):
    # 计算多边形重心
    cx, cy, area = 0, 0, 0
    for i in range(0, n):
        j = (i + 1) % n
        tmp = points[i][0] * points[j][1] - points[j][0] * points[i][1]
        cx += (points[i][0] + points[j][0]) * tmp
        cy += (points[i][1] + points[j][1]) * tmp
        area += tmp
    cx /= 3 * area
    cy /= 3 * area

    # 将多边形按逆时针重新排序
    points = sort_points(n, points, cx, cy)

    # 计算多边形中心
    dx, dy = points[0][0], points[0][1]
    px, py = points[1][0], points[1][1]
    for i in range(2, n):
        qx, qy = points[i][0], points[i][1]
        dx += (px + qx) * (px * qy - qx * py)
        dy += (py + qy) * (px * qy - qx * py)
        px, py = qx, qy
    dx /= 6 * area
    dy /= 6 * area

    return (dx, dy)

def sort_points(n, points, cx, cy):
    # 计算每个点相对于重心的极角
    angles = []
    for i in range(0, n):
        xi, yi = points[i][0], points[i][1]
        angles.append((i, math.atan2(yi - cy, xi - cx)))

    # 按照极角排序,若相同则按距离排序
    angles.sort(key=lambda k: (k[1], (k[1] - angles[0][1]) ** 2 + (points[k[0]][0] - cx) ** 2 + (points[k[0]][1] - cy) ** 2))

    # 按顺序生成序列
    seq = [angles[0][0], angles[1][0]]
    for i in range(2, n):
        for j in range(len(seq) - 1, -1, -1):
            if cross_product(points[seq[j - 1]], points[seq[j]], points[angles[i][0]]) > 0:
                break
            seq.pop(j)
        seq.append(angles[i][0])

    # 重新生成点集
    new_points = []
    for i in range(0, n):
        new_points.append(points[seq[i]])
    return new_points

def cross_product(p1, p2, p3):
    return (p2[0] - p1[0]) * (p3[1] - p2[1]) - (p2[1] - p1[1]) * (p3[0] - p2[0]])

以上代码实现了一个get_polygon_center函数,通过输入多边形顶点的坐标,输出多边形的中心坐标。由于Python中不存在结构体,因此多边形每个顶点以二元组的形式表示。在该函数中,我们先计算多边形的重心坐标,再按照逆时针排序多边形顶点,并生成一条射线,将其绕重心旋转180度并平移到原位置,即可求出多边形的中心坐标。该算法的时间复杂度为O(nlogn)。