BZOJ 1013 高斯消元

来源:互联网 发布:大圣科技知乎 编辑:程序博客网 时间:2024/06/05 08:42

1013: [JSOI2008]球形空间产生器sphere
Description
  有一个球形空间产生器能够在n维空间中产生一个坚硬的球体。现在,你被困在了这个n维球体中,你只知道球面上n+1个点的坐标,你需要以最快的速度确定这个n维球体的球心坐标,以便于摧毁这个球形空间产生器。
Input
  第一行是一个整数n(1<=N=10)。接下来的n+1行,每行有n个实数,表示球面上一点的n维坐标。每一个实数精确到小数点后6位,且其绝对值都不超过20000。
Output
  有且只有一行,依次给出球心的n维坐标(n个实数),两个实数之间用一个空格隔开。每个实数精确到小数点后3位。数据保证有解。你的答案必须和标准输出一模一样才能够得分。
Sample Input
2
0.0 0.0
-1.0 1.0
1.0 0.0
Sample Output
0.500 1.500

通过每一个点到圆心的距离相等可以列出n个方程。用高斯消元解就可以了。

#include <cstdio>#include <cstdlib>#include <iostream>using namespace std;const int N = 30;const double eps = 1e-9;double mat[N][N];int n;double a[N], ans[N];double x;template<typename T>inline T Abs(T x) {    return x < 0 ? -x : x;}void Gauss(void) {    int pos;    for (int i = 1; i < n; i++) {        pos = i;        for (int j = i + 1; j <= n; j++)            if (Abs(mat[j][i]) > Abs(mat[pos][i]) + eps) pos = j;        if (pos != i)            for (int j = i; j <= n + 1; j++)                swap(mat[i][j], mat[pos][j]);        for (int j = i + 1; j <= n; j++)            for (int k = n + 1; k >= i; k--)                mat[j][k] = mat[i][k] * mat[j][i] / mat[i][i] - mat[j][k];    }    for (int i = n; i; i--) {        ans[i] = mat[i][n + 1];        for (int j = i + 1; j <= n; j++)            ans[i] -= ans[j] * mat[i][j];        if (mat[i][i]) ans[i] /= mat[i][i];        else ans[i] = 0;    }}int main(void) {    freopen("1.in", "r", stdin);    scanf("%d", &n);    for (int i = 1; i <= n; i++) scanf("%lf", &a[i]);    for (int i = 1; i <= n; i++)        for (int j = 1; j <= n; j++) {            scanf("%lf", &x);            mat[i][j] = 2.0 * (x - a[j]);            mat[i][n + 1] += x * x - a[j] * a[j];        }    Gauss();    for (int i = 1; i < n; i++) printf("%.3lf ", ans[i]);    printf("%.3lf\n", ans[n]);    return 0;}
0 0