📜  门|门CS 2012 |第 34 题(1)

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

题目介绍

本题名为门,是一道计算几何相关的题目。题目要求我们求出一个多边形的面积和周长,并判断给定的点是否在该多边形内。

题目描述

定义一个多边形,其中顶点按照逆时针顺序给出坐标,求该多边形的面积和周长,并判断给定的点是否在多边形内。

输入格式

输入的第一行包含一个整数 n,表示多边形的顶点数。

接下来 n 行,每行包含两个实数 xi 和 yi,表示该多边形的顶点。

接下来一行包含两个实数 x 和 y,表示需要判断的点的坐标。

输出格式

输出一行,包含两个实数,分别表示该多边形的面积和周长。

接下来一行,“YES” 或者 “NO”。如果需要判断的点在多边形内,输出 “YES”;否则输出 “NO”。

数据范围

多边形的顶点坐标均在 -1000 到 1000 之间。

输入样例1
4
0 0
0 1
1 0
1 1
0.5 0.5
输出样例1
1 4
YES

解题思路

本题需要求一个多边形的面积和周长,还需要判断一个点是否在多边形内,可以通过计算几何中的向量叉积、重心、平移等方法来解决。

具体步骤如下:

  1. 输入多边形的顶点以及需要判断的点的坐标;
  2. 使用叉积计算多边形面积的二倍;
  3. 使用向量计算多边形周长;
  4. 使用三角形重心计算多边形重心;
  5. 平移向量计算需要判断的点与多边形重心之间的向量;
  6. 使用叉积判断该向量是否与多边形各边向量都同向,若均同向,则点在多边形内,反之则不在。

代码实现

from typing import List

def cross(a: List[float], b: List[float], o: List[float]) -> float:
    '''
    计算向量 OA 和向量 OB 的叉积
    '''
    return (a[0]-o[0])*(b[1]-o[1]) - (a[1]-o[1])*(b[0]-o[0])

def area(p: List[List[float]]) -> float:
    '''
    计算多边形的面积
    '''
    n = len(p)
    ans = 0
    for i in range(n):
        ans += cross(p[i-1], p[i], [0, 0])
    return ans / 2

def perimeter(p: List[List[float]]) -> float:
    '''
    计算多边形的周长
    '''
    n = len(p)
    ans = 0
    for i in range(n):
        ans += ((p[i][0]-p[i-1][0])**2 + (p[i][1]-p[i-1][1])**2)**0.5
    return ans

def centroid(p: List[List[float]]) -> List[float]:
    '''
    计算多边形的重心
    '''
    n = len(p)
    x, y = 0, 0
    for i in range(n):
        x += (p[i][0] + p[i-1][0]) * cross(p[i-1], p[i], [0, 0])
        y += (p[i][1] + p[i-1][1]) * cross(p[i-1], p[i], [0, 0])
    a = area(p)
    return [x/(6*a), y/(6*a)]

def in_polygon(p: List[List[float]], q: List[float]) -> bool:
    '''
    判断点 q 是否在多边形 p 内
    '''
    n = len(p)
    ans = True
    for i in range(n):
        if cross(p[i], q, p[i-1]) < 0:
            ans = False
            break
    return ans

if __name__ == '__main__':
    n = int(input())
    p = []
    for i in range(n):
        p.append(list(map(float, input().split())))
    q = list(map(float, input().split()))

    a = area(p)
    l = perimeter(p)

    g = centroid(p)

    v = [q[0]-g[0], q[1]-g[1]]
    s = True
    for i in range(n):
        if cross(p[i], p[i-1], v) < 0:
            s = False
            break

    print('{:.2f} {:.2f}'.format(a, l))
    if s and a > 0:
        print('YES')
    else:
        print('NO')

代码实现使用了 Python 语言,通过面向对象的方式实现向量计算、计算多边形面积、周长、重心等。