洛谷P4035 [JSOI2008]球形空间产生器(高斯消元)
题目描述
有一个球形空间产生器能够在 nn 维空间中产生一个坚硬的球体。现在,你被困在了这个 nn 维球体中,你只知道球面上 n+1n+1 个点的坐标,你需要以最快的速度确定这个 nn 维球体的球心坐标,以便于摧毁这个球形空间产生器。
输入格式
第一行是一个整数 nn (1<=N=10)(1<=N=10)。接下来的 n+1n+1 行,每行有 nn 个实数,表示球面上一点的 nn 维坐标。每一个实数精确到小数点后 66 位,且其绝对值都不超过 2000020000。
输出格式
有且只有一行,依次给出球心的 nn 维坐标( nn 个实数),两个实数之间用一个空格隔开。每个实数精确到小数点后 33 位。数据保证有解。你的答案必须和标准输出一模一样才能够得分。
输入输出样例
输入 #1复制
2
0.0 0.0
-1.0 1.0
1.0 0.0
输出 #1复制
0.500 1.500
直接根据题意列出来的方程组实际上不是线性的,但观察发现给出来的是n + 1个点,因此相邻方程作差(类比差分)能得到n个方程,同时移项后关于xi就是线性的了,进行高斯消元即可。由于数据保证有解,所以只需要按照已知有唯一解的情况进行消元即可。
#include <bits/stdc++.h>
using namespace std;
int n;
double a[20][20], b[20], c[20][20];
int main() {
cin >> n;
for(int i = 1; i <= n + 1; i++) {
for(int j = 1; j <= n; j++) {
cin >> a[i][j];
}
}
//处理出来增广矩阵 c和b共同构成增广矩阵
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= n; j++) {
c[i][j] = 2 * (a[i][j] - a[i + 1][j]);
b[i] += a[i][j] * a[i][j] - a[i + 1][j] * a[i + 1][j];
}
}
for(int i = 1; i <= n; i++) {//因为一定有解:遍历n个主元
for(int j = i; j <= n; j++) {
if(fabs(c[j][i]) > 1e-8) {//不为0
for(int k = i; k <= n; k++) {
swap(c[i][k], c[j][k]);
}
swap(b[i], b[j]);
break;
}
}
for(int j = 1; j <= n; j++) {//注意这里j要从1开始,因为最终要得到的是简化阶梯行列式
if(i == j) continue;
double rate = c[j][i] / c[i][i];
for(int k = i; k <= n; k++) {
c[j][k] -= c[i][k] * rate;
}
b[j] -= b[i] * rate;
}
}
for(int i = 1; i < n; i++) printf("%.3lf ", b[i] / c[i][i]);
printf("%.3lf\n", b[n] / c[n][n]);
return 0;
}