第二十次csp认证 第四题 星际旅行题解

问题描述
试题编号: 202009-4
试题名称: 星际旅行
时间限制: 1.0s
内存限制: 256.0MB
问题描述:
问题描述
在一个 维欧几里得空间的宇宙中,小 A 打算完成一次星际旅行。

利用 维直角坐标系,宇宙中每个点的位置都可以用 维坐标来表示。其中,在宇宙中心的 点(未必是坐标系原点)处,有一个半径为 的超球体黑洞,任何物体若落入黑洞内部(不包括其表面)则无法逃脱。

小 A 选定了 个不在黑洞内部的点
,作为他星际旅行的目标。不会有两个点处于同一位置。

为了提前做好旅行规划,小 A 希望求出这 个点两两之间的最短曲线距离。同样地,这些曲线不能经过黑洞的内部。为了方便,你只需要输出每个点到其他 个点的距离之和。

输入格式
第一行两个整数 。

第二行一个整数 。

第三行 个整数,依次表示超球体黑洞的中心 的每一维坐标。

接下来 行,每行 个整数。第 行的各个整数依次表示点
的每一维坐标。

同一行内的多个整数之间用一个空格隔开。

输出格式
输出一共 行,每行一个实数。第 行表示第 个点(
)到其他所有点的最短曲线距离之和。

请以“整数部分、小数点、小数部分”的格式输出实数,并保留不少于 12 位小数结果。采用其他格式(如科学记数法)输出可能无法得分。

样例输入1
2 3
2
3 1
5 1
1 3
3 -2
Data
样例输出1
8.83711594354348
10.83711594354348
9.39104657990738
Data
样例1说明
如下图所示,圆 为二维平面上的黑洞,
为小 A 星际旅行的目标。

p7.jpg

通过在圆周上选择合适的点 ,可以证明,
曲线
分别为这三对点之间满足条件的最短曲线。
这些曲线的长度分别为 5.14159265358979, 5.69552328995369, 3.69552328995369。

样例输入2
3 8
1
0 0 0
0 0 1
0 1 0
1 0 0
1 1 1
-1 -1 0
-1 0 -1
0 -1 -1
-1 -1 -1
Data
样例输出2
14.12797001266400
14.12797001266400
14.12797001266400
17.90086240651788
13.95502966750398
13.95502966750398
13.95502966750398
14.99490548122857

这是一道几何题,只要认真分析就会发现题目本身不难。题目的测试点给出了三个维度,分别是2,3,100三个维度,乍一看维度超过三维我们人类就无法理解和感知了,其实无论是100维还是2维在数学上的处理是一样的(就本题而言)。我们以最简单的二维进行分析。
任意两个位置a,b和黑洞o的关系有以下三种:
1.a和b的连线不经过黑洞o,
o和a与b的连线的垂线h大于黑洞的半径r,这时点a和b的最短曲线距离就是a与b的直线距离(如下图所示)
要判断出现这种情况的条件,我们要先求出在这里插入图片描述
高度h,可以先求出三角形oab的面积s,这里使用海伦-秦九韶公式求面积。边ab的长度为x,求出面积后,h=2*s/x.
求h的代码块如下:


```cpp
 double x=sqrt(temp);  double p=(d[i]+d[j]+x)/2;
 double s=sqrt(p*(p-x)*(p-d[i])*(p-d[j]));//海伦-秦九韶公式
 double h=2*s/x;

故出现上述这种情况的条件时h>=r.
2.a与b的连线不经过黑洞o,但是a和b的延迟线经过黑洞o,此时a和b的最短曲线距离依旧时a与b的直线距离。
边oa的长度为d[i],边ob的长度为d[j],边ab的长度为x.
出现这种情况的条件时角oab为钝角或直角。
即d[i]*d[i]+d[j]d[j]<=xx;
相似的角oba为钝角或直角的情况也一样。
在这里插入图片描述
在程序中判断出现这两种情况的代码块如下:

if(h>=r||(x*x+d[i]*d[i]<=d[j]*d[j])||(x*x+d[j]*d[j]<=d[i]*d[i]))
 {
     result[i][j]=result[j][i]=x;
     continue}

3.a和b的连线经过黑洞o,如下图
在这里插入图片描述
其中o1为点a和黑洞的切点,o2为点b和黑洞的切点。
a和b的最短曲线距离为a o1+bo2+弧o1 o2,三段之和。
由余弦定理可求出角aob

 double angle1=acos((d[i]*d[i]+d[j]*d[j]-x*x)/(2*d[i]*d[j]));

再根据三角函数可求出角aoo1和角boo2.

double angle2=acos(r/d[i]);
            double angle3=acos(r/d[j]);

角aob减出角aoo1和角aoo2可得角o1 o o2记为angle.
则弧长o1 o2=angle*r.

 result[i][j]=result[j][i]=(angle1-angle2-angle3)*r+rd[i]+rd[j];

下面给出完整代码:

#include<bits/stdc++.h>
using namespace std;
const int N=100+5;
const int M=2000+5;
int n,m;
double o[N],r;
double p[M][N],result[M][M];
double d[M],rd[M];
int main()
{
    //freopen("moyun.txt","r",stdin);
    cin>>n>>m>>r;
    for(int i=1;i<=n;i++)
        cin>>o[i];
    for(int i=1;i<=m;i++)
        for(int j=1;j<=n;j++)
          cin>>p[i][j];
    for(int i=1;i<=m;i++)
    {
        double temp=0;
        for(int j=1;j<=n;j++)
           {
              temp+=(p[i][j]-o[j])*(p[i][j]-o[j]);
           }
           d[i]=sqrt(temp);
           rd[i]=sqrt(d[i]*d[i]-r*r);
    }
    for(int i=1;i<=m;i++)
    {
        for(int j=i+1;j<=m;j++)
        {
            double temp=0;
            for(int k=1;k<=n;k++)
                temp+=(p[i][k]-p[j][k])*(p[i][k]-p[j][k]);
            double x=sqrt(temp);  double p=(d[i]+d[j]+x)/2;
            double s=sqrt(p*(p-x)*(p-d[i])*(p-d[j]));//海伦-秦九韶公式
            double h=2*s/x;
            if(h>=r||(x*x+d[i]*d[i]<=d[j]*d[j])||(x*x+d[j]*d[j]<=d[i]*d[i]))
            {
                result[i][j]=result[j][i]=x;
                continue;
            }
            double angle1=acos((d[i]*d[i]+d[j]*d[j]-x*x)/(2*d[i]*d[j]));
            double angle2=acos(r/d[i]);
            double angle3=acos(r/d[j]);
            result[i][j]=result[j][i]=(angle1-angle2-angle3)*r+rd[i]+rd[j];
        }
    }
    for(int i=1;i<=m;i++)
    {
        double sum=0;
        for(int j=1;j<=m;j++)
        {
            if(i==j) continue;
            sum+=result[i][j];
        }
        printf("%.14f\n",sum);
    }
    return 0;
}


  • 28
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 11
    评论
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值