P4035 [JSOI2008]球形空间产生器(高斯消元)

题目描述

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

输入格式

第一行是一个整数(1≤N≤10)。接下来的 n+1行,每行有 n 个实数,表示球面上一点的 nn 维坐标。每一个实数精确到小数点后 6 位,且其绝对值都不超过 20000。

输出格式

有且只有一行,依次给出球心的 n 维坐标( n 个实数),两个实数之间用一个空格隔开。每个实数精确到小数点后 3 位。数据保证有解。你的答案必须和标准输出一模一样才能够得分。

解析:

设球心 ,因为球心到点的距离相等。 相邻两式相减将未知数移到左边。

有n个未知项n个方程可以解得圆心的位置。

#include<bits/stdc++.h>
using namespace std;
inline double read() {
	char ss = getchar();
	int f = 1;
	double x = 0;
	while (ss < '0' || ss>'9') {
		if (ss == '-') {
			f = -1;
		}
		ss = getchar();
	}
	while (ss >= '0' && ss <= '9') {
		x = x * 10 + ss - '0';
		ss = getchar();
	}
	return x * f;
}

double a[20][20], c[20][20];  // c储存系数 b是每一个方程的值
int n;
double eps = 1e-7;

int main() {
	n = read();
	for (int i = 1; i <= n + 1; i++) {
		for (int j = 1; j <= n; j++) {
			scanf("%lf", &a[i][j]);
		}
	}

	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]);
			c[i][n+1] += a[i][j] * a[i][j] - a[i + 1][j] * a[i + 1][j];// 累加 平方 
		}
	}
		//高斯消元
		for (int i = 1; i <= n; i++) {
			int max = i;
			for (int j = i+1; j <= n; j++) {
				if (fabs(c[j][i]) > fabs(c[max][i])) max = j; //选最大的避免选到0
			}

			//因为这个一定有解所以没有判断是否有解的步骤
			// 交换
			for (int j = 1; j <= n+1; j++) {
				swap(c[i][j], c[max][j]);
			}
			 // c[i][n+1]是等式的值

			//消元

			for (int j = n+1; j >= 1; j--) {
				c[i][j] = c[i][j] / c[i][i]; //对角线化1
			}
			

			for (int j = 1; j <= n; j++) {
				if (j != i) {
					double temp = c[j][i] / c[i][i]; // 乘以系第i列化为0
					for (int k = 1; k <= n+1; k++) {
						c[j][k] -= c[i][k] * temp;
					}
				}
			}
		}
		
		for (int i = 1; i <= n; i++) {
			printf("%0.3lf ",c[i][n+1]);
		}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/zhi6fui/article/details/129476867