CSP认证 202009-4 星际旅行 Python 题解(有注释)

题目在此
其实并没有那么难。。高维和2维的情况都是一样的。
根据两点+中心的三角形的情况进行判断即可
有一部分注释

如果看的人多,,就把各种情况的图画一下吧
思路应该是对的代码没有经过全部样例的验证

代码

'''
    !!!所有距离均为欧式距离
'''
import math
from math import sqrt, acos, cos


#两点距离
def distance(p1, p2) -> float:
    ans = 0.0
    for i in range(n):
        ans += (p1[i] - p2[i])**2
    return sqrt(ans)


# 重要的公式
def getdis(i, j) -> float:
    p1, p2 = point[i], point[j]
    AB_mold = distance(p1, p2)
    # 都在边缘上
    if edge[i] and edge[j]:
        # 求劣弧角度即可
        aerfa = 2 * math.asin((AB_mold / 2) / r)
        return aerfa * r
    else:
        AO_mold = distance(p1, heidong)
        BO_mold = distance(p2, heidong)
        cosA = (AO_mold**2 + AB_mold**2 - BO_mold**2) / (2 * AO_mold * AB_mold)
        cosB = (BO_mold**2 + AB_mold**2 - AO_mold**2) / (2 * BO_mold * AB_mold)

        # A、B两点的连线不经过黑洞,直接返回两者距离,角为钝角或直角
        if cosA < 0 or cosB < 0 or abs(cosA - 0) < 1e-7 or abs(cosB - 0) < 1e-7:
            return AB_mold
        # A、B两点的连线经过黑洞
        else:
            # h是黑洞中心到AB连线的距离
            h = AO_mold * (sqrt(1 - cosA**2))  #sinA,三角函数
            if h >= r:
                return AB_mold
            # 最麻烦的情况,AB两点均在黑洞外且连线经过黑洞
            else:
                cosO = (AO_mold**2 + BO_mold**2 - AB_mold**2) / (2 * AO_mold * BO_mold)
                # E,F点分别为A,B两点在边缘上的切点
                # 如果有一个点在边缘上,那么可以少计算一些
                if edge[i]:
                    AE_mold = 0
                    FB_mold = sqrt(BO_mold**2 - r2)
                    beta = acos(cosO) - acos(r / BO_mold)
                elif edge[j]:
                    FB_mold = 0
                    AE_mold = sqrt(AO_mold**2 - r2)
                    beta = acos(cosO) - acos(r / AO_mold)
                # 两点都不在边缘上
                else:
                    AE_mold = sqrt(AO_mold**2 - r2)
                    FB_mold = sqrt(BO_mold**2 - r2)
                    # beta = acos(cosO) - pi - (acos(r / AO_mold) + acos(r / BO_mold))
                    beta = acos(cosO) - (acos(r / AO_mold) + acos(r / BO_mold))
                    # print(i,j,'都不在edge')
                EF_arc = beta * r
                return EF_arc + FB_mold + AE_mold


if __name__ == "__main__":

    # n维, m个点
    n, m = map(int, input().split(' '))
    # 半径
    r = int(input())
    r2 = r * r
    # 黑洞信息
    heidong = tuple(map(int, input().split(' ')))
    point = [None] * m  #初始化点
    edge = [False] * m  #是否在黑洞边缘
    pi = math.pi
    # 各点的信息
    for i in range(m):
        point[i] = tuple(map(int, input().split(' ')))
        # 判断该点是否在黑洞边缘,即该点到中心的距离是否为r
        if sum([(point[i][j] - heidong[j])**2 for j in range(n)]) == r2:
            edge[i] = True

    dis = [[0] * m for _ in range(m)]
    # 构造点到点的距离矩阵,dis[i][j]表示点i到j的距离
    for i in range(m - 1):
        for j in range(i + 1, m):
            dis[i][j] = dis[j][i] = getdis(i, j)

    # print('打印距离')
    for i in range(m):
        print('%.14f' % (sum(dis[i])))  #14位小数
    # for tt in dis:
    #     print(tt)
    # print(dis)
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值