首页 > Web开发 > 详细

Luogu4035/BZOJ1013 [JSOI2008]球形空间产生器

时间:2019-09-09 13:06:40      阅读:95      评论:0      收藏:0      [点我收藏+]

题目传送门

算法分析

不妨设未知数\(d\)表示每一个点到球心的距离,设未知数\(b_1,b_2,\cdots,b_n\)表示球心的坐标。

我们不难得到\(n+1\)个方程:

\[d^2=\sum_{i=1}^n{(a_i-b_i)^2}\]

发现出现二次项了,这里显然不可以用换元法把二次项换成一次项。

我们把这个式子展开:

\[d^2=\sum_{i=1}^n{a_i^2}+\sum_{i=1}^n{b_i^2}+2\times \sum_{i=1}^n{a_ib_i}\]

未知数写到同一侧:

\[-2\times \sum_{i=1}^n{a_ib_i}-\sum_{i=1}^n{b_i^2}+d^2=\sum_{i=1}^n{a_i^2}\]

这时我们发现,对于每一个方程,所有的二次项系数都是相同的,因此我们考虑邻项相消,得出如下的\(n\)个方程:

\[-2\times \sum_{i=1}^n{(a_i-a_{i-1})b_i}=\sum_{i=1}^n{a_i^2-a_{i-1}^2}\]

这符合高斯消元的条件,直接做即可。

代码实现

#include<bits/stdc++.h>
using namespace std;
#define maxn 105
int n;
double a[maxn][maxn],b[maxn][maxn],x[maxn][maxn];
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n+1;i++){
        for(int j=1;j<=n;j++){
            scanf("%lf",&x[i][j]);
        }
    }
    for(int i=1;i<=n+1;i++){
        for(int j=1;j<=n;j++){
            b[i][j]=(-2)*x[i][j];
        }
        for(int j=1;j<=n;j++)b[i][n+1]-=(x[i][j]*x[i][j]);
    }
    for(int i=1;i<=n+1;i++){
        for(int j=2;j<=n+1;j++){
            a[i][j]=b[i][j]-b[i-1][j];
        }
    }
    for(int i=1;i<=n;i++){
        int p=0;
        for(int j=i;j<=n;j++){if(a[j][i]){p=j;break;}}
        if(!p)continue;
        for(int j=1;j<=n+1;j++)swap(a[i][j],a[p][j]);
        double k=a[i][i];
        for(int j=1;j<=n+1;j++)a[i][j]/=k;
        for(int j=1;j<=n;j++){
            if(i==j)continue;
            double kk=a[j][i];
            for(int l=1;l<=n+1;l++)a[j][l]-=kk*a[i][l];
        }
    }
    for(int i=1;i<=n;i++)printf("%.3lf ",a[i][n+1]);
    return 0;
}

Luogu4035/BZOJ1013 [JSOI2008]球形空间产生器

原文:https://www.cnblogs.com/ZigZagKmp/p/11491053.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!