[Luogu P4035] [BZOJ 1013] [JSOI2008] 球形空间产生器

洛谷传送门
BZOJ传送门

题目描述

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

输入输出格式

输入格式:

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

输出格式:

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

输入输出样例

输入样例#1:

2
0.0 0.0
-1.0 1.0
1.0 0.0

输出样例#1:

0.500 1.500

说明

提示:给出两个定义:

  1. 球心:到球面上任意一点距离都相等的点。
  2. 距离:设两个n维空间上的点 A,B A , B 的坐标为 (a1,a2,,an),(b1,b2,,bn) ( a 1 , a 2 , ⋯ , a n ) , ( b 1 , b 2 , ⋯ , b n ) ,则 AB A B 的距离定义为: dist=(a1b1)2+(a2b2)2++(anbn)2 d i s t = ( a 1 − b 1 ) 2 + ( a 2 − b 2 ) 2 + ⋯ + ( a n − b n ) 2

    解题分析

    高斯消元模板题…

    根据题意, 我们会有 N+1 N + 1 个未知数, 即球心的坐标和半径。 我们可以列出形如以下的 N+1 N + 1 个方程:

    R2=(x1a1)2+(x2a2)2+...+(xnan)2 R 2 = ( x 1 − a 1 ) 2 + ( x 2 − a 2 ) 2 + . . . + ( x n − a n ) 2

    其中 xi x i 表示球心 i i 维的坐标。

    这玩意不好解, 我们拆开以一下:

    R2i=1nxi2=i=1nai22×i=1naixi

    这下左边 N+1 N + 1 个方程作差可以得到0, 右边的 ni=1a2i ∑ i = 1 n a i 2 为常数, 这下就顺利转变成了 N N <script type="math/tex" id="MathJax-Element-28">N</script>个一次方程组, 可以解出来了。

    代码如下:

    #include <cstdio>
    #include <cstring>
    #include <cctype>
    #include <cstdlib>
    #include <cmath>
    #include <algorithm>
    #define R register
    #define IN inline
    #define gc getchar()
    #define W while
    #define MX 15
    #define db double
    db dat[MX][MX], mat[MX][MX], sum[MX];
    int dim, bd;
    void Gauss()
    {
        R int i, j, k;
        for (i = 1; i <= dim; ++i)
        {
            for (j = i + 1; j <= dim; ++j)
            if(fabs(mat[j][i]) > fabs(mat[i][i])) std::swap(mat[i], mat[j]);
            for (j = i + 1; j <= bd; ++j) mat[i][j] /= mat[i][i];
            for (j = 1; j <= dim; ++j)
            {
                if(i ^ j)
                {
                    for (k = i + 1; k <= bd; ++k)
                    mat[j][k] -= mat[j][i] * mat[i][k];
                }
            }
        }
    }
    int main(void)
    {
        scanf("%d", &dim), bd = dim + 1;
        for (R int i = 0; i <= dim; ++i)
        for (R int j = 1; j <= dim; ++j)
        scanf("%lf", &dat[i][j]), sum[i] += dat[i][j] * dat[i][j];
        for (R int i = 1; i <= dim; ++i)
        {
            for (R int j = 1; j <= dim; ++j)
            mat[i][j] = 2 * (dat[i][j] - dat[i - 1][j]);
            mat[i][bd] = sum[i] - sum[i - 1];
        }
        Gauss();
        for (R int i = 1; i <= dim; ++i) printf("%.3lf ", mat[i][bd]);
    }
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值