【JSOI 2008】球形空间产生器

【题目】

传送门

题目描述:

有一个球形空间产生器能够在 n n n 维空间中产生一个坚硬的球体。现在,你被困在了这个 n n n 维球体中,你只知道球面上 n + 1 n+1 n+1 个点的坐标,你需要以最快的速度确定这个 n n n 维球体的球心坐标,以便于摧毁这个球形空间产生器。

输入格式:

第一行是一个整数 n n n

接下来的 n + 1 n+1 n+1 行,每行有 n n n 个实数,表示球面上一点的 n n n 维坐标。每一个实数精确到小数点后 6 6 6 位,且其绝对值都不超过 20000 20000 20000

输出格式:

有且只有一行,依次给出球心的 n n n 维坐标( n n n 个实数),两个实数之间用一个空格隔开。

每个实数精确到小数点后 3 3 3 位。数据保证有解。你的答案必须和标准输出一模一样才能够得分。

样例数据:

输入
2
0.0 0.0
-1.0 1.0
1.0 0.0

输出
0.500 1.500

备注:

【数据规模】
对于 40 % 40\% 40% 的数据, 1 ≤ n ≤ 3 1≤n≤3 1n3
对于 100 % 100\% 100% 的数据, 1 ≤ n ≤ 10 1≤n≤10 1n10

【提示】
给出两个定义:
1 1 1、球心:到球面上任意一点距离都相等的点。
2 2 2、距离:设两个 n n n 为空间上的点 A, B 的坐标为 ( a 1 , a 2 , … , a n ) , ( b 1 , b 2 , … , b n ) (a_1, a_2, …, a_n), (b_1, b_2, …, b_n) (a1,a2,,an),(b1,b2,,bn),则 AB 的距离定义为: d i s t = ( a 1 − b 1 ) 2 + ( a 2 − b 2 ) 2 + … + ( a n − b n ) 2 dist = \sqrt{(a_1-b_1)^2 + (a_2-b_2)^2 + … + (a_n-b_n)^2} dist=(a1b1)2+(a2b2)2++(anbn)2


【分析】

简单说一下推导过程吧

假设有两个点 A ( a 1 , a 2 , … , a n ) (a_1, a_2, …, a_n) (a1,a2,,an),B ( b 1 , b 2 , … , b n ) (b_1, b_2, …, b_n) (b1,b2,,bn),球心坐标为 ( x 1 , x 2 , . . . , x n ) (x_1,x_2,...,x_n) (x1,x2,...,xn)

那么容易得到 ( a 1 − x 1 ) 2 + ( a 2 − x 2 ) 2 + . . . + ( a n − x n ) 2 = ( b 1 − x 1 ) 2 + ( b 2 − x 2 ) 2 + . . . + ( b n − x n ) 2 (a_1-x_1)^2+(a_2-x_2)^2+...+(a_n-x_n)^2=(b_1-x_1)^2+(b_2-x_2)^2+...+(b_n-x_n)^2 (a1x1)2+(a2x2)2+...+(anxn)2=(b1x1)2+(b2x2)2+...+(bnxn)2

拆开后再化简可得 ( 2 b 1 − 2 a 1 ) x 1 + ( 2 b 2 − 2 a 2 ) x 2 + . . . + ( 2 b n − 2 a n ) x n = ( b 1 ) 2 + ( b 2 ) 2 + . . . + ( b n ) 2 − ( a 1 ) 2 − ( a 2 ) 2 − . . . − ( a n ) 2 (2b_1-2a_1)x_1+(2b_2-2a_2)x_2+...+(2b_n-2a_n)x_n=(b_1)^2+(b_2)^2+...+(b_n)^2-(a_1)^2-(a_2)^2-...-(a_n)^2 (2b12a1)x1+(2b22a2)x2+...+(2bn2an)xn=(b1)2+(b2)2+...+(bn)2(a1)2(a2)2...(an)2

可以举点小数据来推,比如让 n = 2 n=2 n=2 来推一遍,这样可能好理解一点

容易看出,两个点列等式可以得到一个关于 x x x 的线性方程,这样把所有的点都列一遍,就有 n n n 个方程,用高斯消元就行

应该不算很难吧


【代码】

#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 105
using namespace std;
int n;
double ans[N],g[N][N],a[N][N];
void Guass()
{
	int i,j,k;
	for(i=1;i<=n;++i)
	{
		k=i;
		for(j=i+1;j<=n;++j)
		  if(fabs(g[k][i])<fabs(g[j][i]))
		    k=j;
		swap(g[i],g[k]);
		for(j=i+1;j<=n;++j)
		  for(k=i+1;k<=n+1;++k)
		    g[j][k]-=g[i][k]*g[j][i]/g[i][i];
	}
	for(i=n;i;--i)
	{
		for(j=i+1;j<=n;++j)
		  g[i][n+1]-=ans[j]*g[i][j];
		ans[i]=g[i][n+1]/g[i][i];
	}
}
int main()
{
	int i,j;
	scanf("%d",&n);
	for(i=0;i<=n;++i)
	  for(j=1;j<=n;++j)
	    scanf("%lf",&a[i][j]);
	double temp;
	for(i=1;i<=n;++i)
	{
		temp=0;
		for(j=1;j<=n;++j)
		{
			g[i][j]=-2*a[i-1][j]+2*a[i][j];
			temp+=a[i][j]*a[i][j]-a[i-1][j]*a[i-1][j];
		}
		g[i][n+1]=temp;
	}
	Guass();
	for(i=1;i<=n;++i)
	  printf("%.3lf ",ans[i]);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值