问题描述
试题编号: 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;
}