当前位置: 代码迷 >> 综合 >> [bzoj 1013] [JSOI2008]球形空间产生器sphere:高斯消元
  详细解决方案

[bzoj 1013] [JSOI2008]球形空间产生器sphere:高斯消元

热度:43   发布时间:2024-01-05 02:26:36.0

题意:n维空间中有一个球面,给(n+1)个球面上的点的坐标,求球心坐标。n维空间中的球面定义为到定点(球心)的欧几里德距离等于定值(半径)的点的集合。数据保证有解。

看起来可以待定系数法,但是会不会产生二次项呢?

对于每个点 (a1,a2,,an) ,可以列方程:

(x1?a1)2+(x2?a2)2+?+(xn?an)2=r2

把含未知量的项放到一边,常数项放到另一边,得:
2a1x1+2a2x2+?2anxn?(x21+x22+?+x2n)+r2=a21+a2+?+a2n

如果把括号内的一串平方和看作整体,也还是有(n+2)个变量,(n+1)个方程搞不定诶……

但是每个方程都含有 ?(x21+x22+?+x2n)+r2 ,一作差不就消掉了吗?这样有n个方程,n个未知数,不错。

等等……把 ?(x21+x22+?+x2n)+r2 看作一个整体不就好了吗?

整体思想掌握地比我好的读者请略过上述三段。

其实都可以啦……黄学长是作的差。这样可以减少一个未知数。

为了方便行的交换,我把增广矩阵的每一行申请为动态内存。

#include <cstdio>
#include <algorithm>
#include <cmath>
using namespace std;
const double eps = 1e-9;
const int MAX_N = 10;
double* M[MAX_N+1];
int n;void gauss()
{for (int i = 0, j; i <= n; ++i) {for (j = i; j <= n && fabs(M[j][i]) < eps; ++j);swap(M[i], M[j]);double t = M[i][i];M[i][i] = 1;for (j = i+1; j <= n+1; ++j)M[i][j] /= t;for (j = 0; j <= n; ++j) {if (j == i)continue;double r = M[j][i];M[j][i] = 0;for (int k = i+1; k <= n+1; ++k)M[j][k] -= r*M[i][k];}}
}int main()
{scanf("%d", &n);for (int i = 0; i <= n; ++i) {M[i] = new double[n+2]();M[i][0] = 1;for (int j = 1; j <= n; ++j) {scanf("%lf", &M[i][j]);M[i][n+1] += M[i][j] * M[i][j];M[i][j] *= 2;}}gauss();for (int i = 1; i <= n; ++i)printf("%.3f%c", M[i][n+1], " \n"[i == n]);return 0;
}