算法分析
不妨设未知数\(d\)表示每一个点到球心的距离,设未知数\(b_1,b_2,\cdots,b_n\)表示球心的坐标。
我们不难得到\(n+1\)个方程:
\[d^2=\sum_{i=1}^n{(a_i-b_i)^2}
\]
发现出现二次项了,这里显然不可以用换元法把二次项换成一次项。
我们把这个式子展开:
\[d^2=\sum_{i=1}^n{a_i^2}+\sum_{i=1}^n{b_i^2}+2\times \sum_{i=1}^n{a_ib_i}
\]
未知数写到同一侧:
\[-2\times \sum_{i=1}^n{a_ib_i}-\sum_{i=1}^n{b_i^2}+d^2=\sum_{i=1}^n{a_i^2}
\]
这时我们发现,对于每一个方程,所有的二次项系数都是相同的,因此我们考虑邻项相消,得出如下的\(n\)个方程:
\[-2\times \sum_{i=1}^n{(a_i-a_{i-1})b_i}=\sum_{i=1}^n{a_i^2-a_{i-1}^2}
\]
这符合高斯消元的条件,直接做即可。
代码实现
#include<bits/stdc++.h>
using namespace std;
#define maxn 105
int n;
double a[maxn][maxn],b[maxn][maxn],x[maxn][maxn];
int main(){
scanf("%d",&n);
for(int i=1;i<=n+1;i++){
for(int j=1;j<=n;j++){
scanf("%lf",&x[i][j]);
}
}
for(int i=1;i<=n+1;i++){
for(int j=1;j<=n;j++){
b[i][j]=(-2)*x[i][j];
}
for(int j=1;j<=n;j++)b[i][n+1]-=(x[i][j]*x[i][j]);
}
for(int i=1;i<=n+1;i++){
for(int j=2;j<=n+1;j++){
a[i][j]=b[i][j]-b[i-1][j];
}
}
for(int i=1;i<=n;i++){
int p=0;
for(int j=i;j<=n;j++){if(a[j][i]){p=j;break;}}
if(!p)continue;
for(int j=1;j<=n+1;j++)swap(a[i][j],a[p][j]);
double k=a[i][i];
for(int j=1;j<=n+1;j++)a[i][j]/=k;
for(int j=1;j<=n;j++){
if(i==j)continue;
double kk=a[j][i];
for(int l=1;l<=n+1;l++)a[j][l]-=kk*a[i][l];
}
}
for(int i=1;i<=n;i++)printf("%.3lf ",a[i][n+1]);
return 0;
}