有一个球形空间产生器能够在n维空间中产生一个坚硬的球体。
现在,你被困在了这个n维球体中,你只知道球面上n+1个点的坐标,你需要以最快的速度确定这个n维球体的球心坐标,以便于摧毁这个球形空间产生器。
输入格式
第一行是一个整数n。
接下来的n+1行,每行有n个实数,表示球面上一点的n维坐标。
每一个实数精确到小数点后6位,且其绝对值都不超过20000。
输出格式
有且只有一行,依次给出球心的n维坐标(n个实数),两个实数之间用一个空格隔开。
每个实数精确到小数点后3位。
数据保证有解。
数据范围
1≤n≤101≤n≤10
输入样例:
2
0.0 0.0
-1.0 1.0 1.0 0.0
输出样例:
0.500 1.500
题意:n维空间,给你n+1个点,这n+1个点都在圆面上,求这个圆心坐标是多少
思路:首先每个点都在圆面上,点到圆心的距离相等
点与圆心的方程为 (x-a)^2+(y-b)^2 = r^2
然后我们可以把这n+1个点带入,得出n+1个式子
求线性方程组的算法高斯消元,但是我们还要化简成高斯消元所满足的最简式子,我们可以通过相邻两个方程减,可以得出
2*(a11-a21)x1 + 2*(a12-a22)x2 ......2*(a1n-a2n)xn = a11^2-b11^2 + a12^2-b12^2 ...... a1n^2-b12^2
得出n个类似的式子
我们就可以通过高斯消元最后得出答案
通过化成矩阵最后化成一个最简矩阵,上面就是化简的过程
我们通过三种初等行变换进行操作来得出的答案
1,用一个非零的数乘以这行的所有数
2,把其中一行的x倍加到另一行
3,交换两行的位置
#include<bits/stdc++.h> #define maxn 100005 #define mod 1000000007 #define eps 1e-8 using namespace std; typedef long long ll; double d[20][20],a[20][20],b[20]; int main(){ ll n; cin>>n; for(int i=0;i<=n;i++){ for(int j=1;j<=n;j++){ cin>>d[i][j]; } } for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ a[i][j]=2*(d[i-1][j]-d[i][j]); b[i]+=d[i-1][j]*d[i-1][j]-d[i][j]*d[i][j]; } } for(int i=1;i<=n;i++){ for(int j=i;j<=n;j++){ if(fabs(a[j][i])>eps){//我们要选一个系数不为0的数来进行操作,这个精度一般选择在 1e-4到1e-9之间,因为有些是0的数有可能还被认为系数不为0,有些不是0还被认为是0,必须要用精度判断 for(int k=1;k<=n;k++){ double t=a[i][k]; a[i][k]=a[j][k]; a[j][k]=t; } double t=b[i]; b[i]=b[j]; b[j]=t; } }
//这个题是保证有解,有可能还有两种情况,如果某一行都为0,那么就有无穷多个解,如果某一行都为0,但是常数不是0,那么就造成 0 = c 的形式,说明方程无解,这另外两种情况都需要自己判断 for(int j=1;j<=n;j++){ if(i==j) continue; double state=a[j][i]/a[i][i]; for(int k=1;k<=n;k++){ a[j][k]-=state*a[i][k]; } b[j]-=b[i]*state; } } for(int i=1;i<=n;i++){ printf("%.3lf ",b[i]/a[i][i]); } }