【ybt金牌导航8-2-1】【luogu P4035】球形空间产生器

球形空间产生器

题目链接:ybt金牌导航8-2-1 / luogu P4035

题目大意

在一个 n 维的地方有 n+1 个点在一个 n 维球的球面上,要你求这个 n 维球的球心坐标。

球心到球面的距离相等,然后距离就是像勾股定理一样,根号里面有多少维就弄多少个。

思路

这题我们先看到距离相等这个东西,那我们考虑列式子。

那它是形如这样的:(设球心坐标为 ( m 1 , m 2 , . . . , m n ) (m_1,m_2,...,m_n) (m1,m2,...,mn)
( m 1 − a 1 ) 2 + ( m 2 − a 2 ) 2 + . . . + ( m n − a n ) 2 = ( m 1 − b 1 ) 2 + ( m 2 − b 2 ) 2 + . . . + ( m n − b n ) 2 (m_1-a_1)^2+(m_2-a_2)^2+...+(m_n-a_n)^2=(m_1-b_1)^2+(m_2-b_2)^2+...+(m_n-b_n)^2 (m1a1)2+(m2a2)2+...+(mnan)2=(m1b1)2+(m2b2)2+...+(mnbn)2
然后你可以一直列,不同的你可以列 n n n 个。

然后你看到 n n n 个未知数 n n n 个方程,你会想到用高斯消元。
但是它有平方啊!
其实你把式子化开,你会发现未知数的二次项会被消掉。
会变成这样:

− a 1 × m 1 × 2 + a 1 2 − a 2 × m 2 × 2 + a 2 2 − . . . − a n × m n × 2 + a n 2 = − b 1 × m 1 × 2 + b 1 2 − b 2 × m 2 × 2 + b 2 2 − . . . − b n × m n × 2 + b n 2 -a_1\times m_1\times2+a_1^2-a_2\times m_2\times2+a_2^2-...-a_n\times m_n\times2+a_n^2=-b_1\times m_1\times2+b_1^2-b_2\times m_2\times2+b_2^2-...-b_n\times m_n\times2+b_n^2 a1×m1×2+a12a2×m2×2+a22...an×mn×2+an2=b1×m1×2+b12b2×m2×2+b22...bn×mn×2+bn2

− a 1 × m 1 × 2 + b 1 × m 1 × 2 − a 2 × m 2 × 2 + b 2 × m 2 × 2 − . . . − a n × m n × 2 + b n × m n × 2 = − a 1 2 + b 1 2 − a 2 2 + b 2 2 − . . . − a n 2 + b n 2 -a_1\times m_1\times2+b_1\times m_1\times2-a_2\times m_2\times2+b_2\times m_2\times2-...-a_n\times m_n\times2+b_n\times m_n\times2=-a_1^2+b_1^2-a_2^2+b_2^2-...-a_n^2+b_n^2 a1×m1×2+b1×m1×2a2×m2×2+b2×m2×2...an×mn×2+bn×mn×2=a12+b12a22+b22...an2+bn2

(每个式子都这样弄一下,就有 n n n 个这样的式子)

那你就可以把式子弄高斯消元,也就得出答案了。

我这里是一遍统一拿第一个点,另一边就各是不同的点。

代码

#include<cstdio>
#include<algorithm>

using namespace std;

int n, maxx;
double last[21], f[21][21];
double maxn, x;

double abss(double x) {
    
    
	if (x < 0) return -x;
	return x;
}

void gauss(int n) {
    
    //高斯消元
	for (int i = 1; i <= n; i++) {
    
    
		maxn = -1e9;
		for (int j = i; j <= n; j++)
			if (maxn < abss(f[j][i])) {
    
    
				maxn = abss(f[j][i]);
				maxx = j;
			}
		
		for (int j = 1; j <= n + 1; j++)
			swap(f[i][j], f[maxx][j]);
		
		double tmp = f[i][i];
		for (int j = 1; j <= n + 1; j++)
			f[i][j] /= tmp;
		
		for (int j = 1; j <= n; j++) {
    
    
			if (i == j) continue;
			
			tmp = f[j][i];
			for (int k = 1; k <= n + 1; k++)
				f[j][k] -= tmp * f[i][k];
		}
	}
}

int main() {
    
    
	scanf("%d", &n);
	
	for (int i = 1; i <= n; i++) {
    
    
		scanf("%lf", &x);
		last[i] -= 2 * x;//根据两个距离相等列数字
		last[n + 1] -= x * x;//这个是给出一遍
	}
	for (int i = 2; i <= n + 1; i++) {
    
    
		for (int j = 1; j <= n; j++) {
    
    
			scanf("%lf", &x);
			
			f[i - 1][j] += 2 * x;//补上另一边
			f[i - 1][j] += last[j];
			f[i - 1][n + 1] += x * x;
		}
		f[i - 1][n + 1] += last[n + 1]; 
	}
	
	gauss(n);
	
	for (int i = 1; i <= n; i++)
		printf("%.3lf ", f[i][n + 1] / f[i][i]);
	
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_43346722/article/details/114099775