Loading

洛谷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;
}
posted @ 2021-07-11 16:45  脂环  阅读(54)  评论(0编辑  收藏  举报