[bzoj1013](JSOI2008)球形空间产生器sphere(高斯消元)
Description
有一个球形空间产生器能够在n维空间中产生一个坚硬的球体。现在,你被困在了这个n维球体中,你只知道球面上n+1个点的坐标,你需要以最快的速度确定这个n维球体的球心坐标,以便于摧毁这个球形空间产生器。
Input
第一行是一个整数,n。接下来的n+1行,每行有n个实数,表示球面上一点的n维坐标。每一个实数精确到小数点后6位,且其绝对值都不超过20000。
Output
有且只有一行,依次给出球心的n维坐标(n个实数),两个实数之间用一个空格隔开。每个实数精确到小数点后3位。数据保证有解。你的答案必须和标准输出一模一样才能够得分。
Sample Input
0.0 0.0
-1.0 1.0
1.0 0.0
Sample Output
HINT
数据规模:
对于40%的数据,1<=n<=3
对于100%的数据,1<=n<=10
提示:给出两个定义:
1、 球心:到球面上任意一点距离都相等的点。
2、 距离:设两个n为空间上的点A, B的坐标为$(a_1, a_2, …, a_n), (b_1, b_2, …, b_n)$,则AB的距离定义为:$$dist = \sqrt{ (a_1-b_1)^2 + (a_2-b_2)^2 + … + (a_n-b_n)^2 }$$
分析
设球心坐标为$(x_1, x_2, ... , x_n)$,根据定义可以列出方程组:
$$ \forall i,j \in [1,n+1]: \sum_{k=1}^N (x_k - a_{ik})^2 = \sum_{k=1}^N (x_k - a_{jk})^2$$.
展开后移项相减,得到
$$\sum_{k=1}^N 2(a_{ik} - a_{jk})x_k = a_{ik}^2 - a_{jk}^2 $$
由于变量有N个,我们只需选取其中N组线性无关(或可以使所有无向边(i,j)构成一棵树)的(i,j)方程来求解即可。
题目本身不难,可是为学校OJ造测试数据这种事简直醉人……我的做法是先随机出一个N维向量作为答案,再随机出半径R,接着循环N+1次,每次随机一个N-1维向量,求出这条直线与球的交点……最终还要运行一遍本题的高斯消元判断这些点是否线性相关……
好吧其实真正的问题是我太水了……敲错了datamaker调试了好久= =
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
2 Problem: 1013
3 User: AsmDef
4 Language: C++
5 Result: Accepted
6 Time:0 ms
7 Memory:1272 kb
8 ****************************************************************/
9
10 //Asm_Def
11 #include <iostream>
12 #include <cctype>
13 #include <cstdio>
14 #include <vector>
15 #include <algorithm>
16 #include <cmath>
17 #include <queue>
18 using namespace std;
19 template<typename T>inline void getd(T &x){
20 char c = getchar();
21 bool minus = 0;
22 while(!isdigit(c) && c != '-')c = getchar();
23 if(c == '-')minus = 1, c = getchar();
24 x = c - '0';
25 while(isdigit(c = getchar()))x = x * 10 + c - '0';
26 if(minus)x = -x;
27 }
28 /*======================================================*/
29 const double eps = 1e-12;
30 double *Eq[11], Ans[11];
31 int N;
32 inline void init(){
33 double a, P[11][12];
34 getd(N);int i, j;
35 for(j = 0;j < N;++j)scanf("%lf", *P + j);
36 for(i = 1;i <= N;++i){
37 for(j = 0;j < N;++j)
38 scanf("%lf", P[i] + j);
39 P[i-1][N] = 0;
40 for(j = 0;j < N;++j){
41 a = P[i-1][j] + P[i][j];
42 P[i-1][j] = P[i][j] - P[i-1][j];
43 P[i-1][N] += a * P[i-1][j] / 2.0;
44 }
45 Eq[i-1] = P[i-1];
46 }
47 }
48 inline void solve(){
49 int i, j, k;
50 double frac;
51 for(i = 0;i < N;++i){
52 for(j = i+1;j < N;++j)
53 if(fabs(Eq[i][i]) < fabs(Eq[j][i]))swap(Eq[i], Eq[j]);
54
55 if(fabs(Eq[i][i]) < eps){
56 cout << "No Answer" << endl;
57 exit(1);
58 }
59 for(j = i+1;j < N;++j){
60 if(fabs(frac = Eq[j][i] / Eq[i][i]) < eps)continue;
61 Eq[j][i] = 0;
62 for(k = i+1;k <= N;++k)
63 Eq[j][k] -= frac * Eq[i][k];
64 }
65 }
66 for(i = N-1;i >= 0;--i){
67 Ans[i] = Eq[i][N] / Eq[i][i];
68 for(j = 0;j < i;++j)
69 Eq[j][N] -= Eq[j][i] * Ans[i];
70 }
71 for(i = 0;i < N;++i)
72 printf("%.3lf%c", Ans[i], i == N-1 ? '\n' : ' ');
73 }
74 int main(){
75 #if defined DEBUG
76 //freopen("test", "r", stdin);
77 #else
78 //freopen("bzoj_1013.in", "r", stdin);
79 //freopen("bzoj_1013.out", "w", stdout);
80 #endif
81 init();
82 solve();
83
84 #if defined DEBUG
85 //cout << endl << (double)clock()/CLOCKS_PER_SEC << endl;
86 #endif
87 return 0;
88 }