Bzoj P1013 [JSOI2008]球形空间产生器sphere___高斯消元

题目大意:

给出一个n维球体中球面上的 n + 1 个点的坐标,问n维球体的球心坐标。

1 N 10
每一个坐标为一个实数精确到小数点后6位且其绝对值都不超过20000。

分析:

那么我们设距离为 D ,球心的 N 维坐标为
x 1 , x 2 , x 3 , . . . , x n
那么显然对于任意一点i的 N 维坐标( a [ i , 1 ] , a [ i , 2 ] , a [ i , 3 ] , . . . , a [ i , n ] ),
必然有 j = 1 n ( a [ i , j ] x j ) 2 = D 2
显然球面上任意一点到球心的距离相等,
所以我们可以通过相邻两个方程作差变成N个N元一次方程,
因为
j = 1 n ( a [ i , j ] x j ) 2 = D 2 = j = 1 n ( a [ k , j ] x j ) 2
那么我们对于点 i , k ,显然是有
j = 1 n ( a [ i , j ] x j ) 2 j = 1 n ( a [ k , j ] x j ) 2 = 0
那么显然 j = 1 n ( ( a [ i , j ] x j ) 2 ( a [ k , j ] x j ) 2 ) = 0
化简一下,可以得到
j = 1 n ( ( a [ i , j ] 2 a [ k , j ] 2 2 x j ( a [ i , j ] a [ k , j ] ) ) = 0
即可以转换成
j = 1 n 2 x j ( a [ i , j ] a [ k , j ] ) = j = 1 n ( ( a [ i , j ] 2 a [ k , j ] 2 )

那么我们可以将点 i ,跟点 i + 1 ,通过这种转换变成一个N元一次方程,
总共可以得到N个这种方程,然后高斯消元就好

代码:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#define eps 1e-8
#define N 15

using namespace std;

double a[N][N], c[N][N], b[N];
int n;

int main(){
    scanf("%d", &n);
    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]);
              b[i] += a[i][j] * a[i][j] - a[i+1][j] * a[i+1][j];
         }
    for (int i = 1; i <= n; i++) {
         for (int j = i + 1; j <= n; j++) 
              if (fabs(c[j][i]) > eps) {
                  for (int k = 1; k <= n; k++) swap(c[i][k], c[j][k]);
                   swap(b[i], b[j]);    
              }
         for (int j = 1; j <= n; j++) 
              if (i != j) {
                  double rp = c[j][i] / c[i][i];
                  for (int k = i; k <= n; k++) c[j][k] -= c[i][k] * rp;
                  b[j] -= b[i] * rp;
              }
    }
    for (int i = 1; i < n; i++) printf("%.3f ", b[i] / c[i][i]);
    printf("%.3f", b[n] / c[n][n]);
    return 0; 
} 


猜你喜欢

转载自blog.csdn.net/gx_man_vip/article/details/80357534
今日推荐