AcWing 207. 球形空间产生器 (高斯消元)打卡

有一个球形空间产生器能够在n维空间中产生一个坚硬的球体。

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

输入格式

第一行是一个整数n。

接下来的n+1行,每行有n个实数,表示球面上一点的n维坐标。

每一个实数精确到小数点后6位,且其绝对值都不超过20000。

输出格式

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

每个实数精确到小数点后3位。

数据保证有解。

数据范围

1n101≤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]); } }


 
原文地址:https://www.cnblogs.com/Lis-/p/11098053.html