BZOJ1013【JSOI2008】球形空间产生器 <高斯消元>

Problem

【JSOI2008】球形空间产生器

Time  Limit:  1  Sec\mathrm{Time\;Limit:\;1\;Sec}
Memory  Limit:  162  MB\mathrm{Memory\;Limit:\;162\;MB}

Description

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

Input

第一行是一个整数n  (1n10)n\;(1\le n\le10)
接下来的n+1n+1行,每行有nn个实数,表示球面上一点的nn维坐标。
每一个实数精确到小数点后66位,且其绝对值都不超过2000020000

Output

有且只有一行,依次给出球心的nn维坐标(nn个实数),两个实数之间用一个空格隔开。
每个实数精确到小数点后33位,数据保证有解,你的答案必须和标准输出一模一样才能够得分。

Sample Input

1
2
3
4
2
0.0 0.0
-1.0 1.0
1.0 0.0

Sample Output

1
0.500 1.500

HINT

给出两个定义:

  • 球心:到球面上任意一点距离都相等的点。
  • 距离:设两个nn维空间上的点A,BA,B的坐标为(a1,a2,,an)(a_1,a_2,\cdots,a_n),(b1,b2,,bn)(b_1,b_2,\cdots,b_n),则ABAB的距离定义为:dist=(a1b1)2+(a2b2)2++(anbn)2dist=\sqrt{(a_1-b_1)^2+(a_2-b_2)^2+\cdots+(a_n-b_n)^2}

标签:高斯消元

Solution

高消裸题。

将第n+1n+1个点单独分出来,将其与前nn个点分别联立形成nn个方程,高消即可求得球心坐标。

设球心为(x1,x2,,xn)(x_1, x_2,\cdots,x_n),第n+1n+1个点为(t1,t2,,tn)(t_1,t_2,\cdots,t_n)。对于前nn个点中的一个点AA,设AA坐标为(a1,a2,,an)(a_1, a_2,\cdots,a_n)。那么一定有

(a1x1)2+(a2x2)2++(anxn)2=(t1x1)2+(t2x2)2++(tnxn)2(a_1-x_1)^2+(a_2-x_2)^2+\cdots+(a_n-x_n)^2=(t_1-x_1)^2+(t_2-x_2)^2+\cdots+(t_n-x_n)^2

展开得

i=1nai2+i=1nxi22i=1naixi=i=1nti2+i=1nxi22i=1ntixi\sum_{i=1}^{n}a_i^2+\sum_{i=1}^{n}x_i^2-2\sum_{i=1}^{n}a_ix_i=\sum_{i=1}^{n}t_i^2+\sum_{i=1}^{n}x_i^2-2\sum_{i=1}^{n}t_ix_i

移项化简

2i=1n(aiti)xi=i=1nai2i=1nti22\sum_{i=1}^{n}(a_i-t_i)x_i=\sum_{i=1}^{n}a_i^2-\sum_{i=1}^{n}t_i^2

直接高斯消元解方程组,时间复杂度O(n3)O(n^3)

\bigstar注意行末不要输出空格

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <bits/stdc++.h>
#define EPS 1e-8
using namespace std;
typedef double dnt;
int n; dnt p[15][15], f[15][15];
dnt sqr(dnt x) {return x*x;}
bool Gauss() {
for (int i = 1, t; i <= n; i++) {
for (t = i; t <= n; t++) if (fabs(f[t][i]) >= EPS) break;
if (t > n) return false; swap(f[i], f[t]);
for (int j = 1; j <= n; j++) if (i^j) {
dnt div = f[j][i]/f[i][i];
for (int k = 1; k <= n+1; k++)
f[j][k] -= f[i][k]*div;
}
}
for (int i = 1; i <= n; i++) f[i][n+1] /= f[i][i];
return true;
}
int main() {
scanf("%d", &n);
for (int i = 1; i <= n+1; i++)
for (int j = 1; j <= n; j++)
scanf("%lf", p[i]+j);
for (int i = 1, j = n+1; i <= n; i++)
for (int k = 1; k <= n; k++)
f[i][k] = p[i][k]-p[j][k],
f[i][n+1] += (sqr(p[i][k])-sqr(p[j][k]))/2;
Gauss();
for (int i = 1; i <= n; i++)
if (i^n) printf("%.3lf ", f[i][n+1]);
else printf("%.3lf", f[i][n+1]);
return 0;
}