Luogu P4035 [JSOI2008]球形空间产生器
题目描述
有一个球形空间产生器能够在 \(n\) 维空间中产生一个坚硬的球体。现在,你被困在了这个 \(n\) 维球体中,你只知道球面上 \(n+1\) 个点的坐标,你需要以最快的速度确定这个 \(n\) 维球体的球心坐标,以便于摧毁这个球形空间产生器。
输入格式
第一行是一个整数\(n \left( 1 \le N \le 10 \right)\)。接下来的 \(n+1\) 行,每行有 \(n\) 个实数,表示球面上一点的 \(n\) 维坐标。每一个实数精确到小数点后 \(6\) 位,且其绝对值都不超过 \(20000\)。
输出格式
有且只有一行,依次给出球心的 \(n\) 维坐标( \(n\) 个实数),两个实数之间用一个空格隔开。每个实数精确到小数点后 \(3\) 位。数据保证有解。你的答案必须和标准输出一模一样才能够得分。
题目链接
思路
根据题意得
\[(x_{1}-a_{1})^2+(x_{2}-a_{2})^2+.......+(x_{n}-a_{n})^2=r^2
\]
可化为
$ 2a_{1}x_{1}+2a_{2}x_{2}+......+2a_{n}x_{n}-r2-x_{1}-x_{2}{2}-......-x_{n}=a_{1}{2}+.......a_{n} $
设 $ t=-r2-x_{1}-x_{2}{2}-......-x_{n} $
所以得到
$ 2a_{1}x_{1}+2a_{2}x_{2}+......+2a_{n}x_{n}+t=a_{1}{2}+.......a_{n} $
因此可以得到一个 \(n+1\)元方程组
利用高斯消元求解,别忘了总数是 \(n+1\) 而不是 \(n\) (调了半小时的祸根)
(\(\mathrm{LaTeX}\)好难打呀)
code
#include<bits/stdc++.h>
using namespace std;
const int MAXN=20;
double a[MAXN][MAXN],num;
int n;
void debug()
{
puts("---------------------------------");
for(int i=1;i<=n+1;++i){
for(int j=1;j<=n+2;++j){
cout<<fixed<<setprecision(2)<<a[i][j]<<" ";
}
putchar('\n');
}
}
void gauss()
{
for(int i=1;i<=n+1;i++){
// debug();
int now=i;
while(a[now][i]==0&&now<=n+1){
now++;
}
if(now==n+2){
puts("???");
exit(233);
}
for(int j=1;j<=n+2;j++){
swap(a[i][j],a[now][j]);
}
double k=a[i][i];
for(int j=1;j<=n+2;j++){
a[i][j]/=k;
}
for(int j=1;j<=n+1;j++){
if(j!=i){
double kkk=a[j][i];
for(int k=1;k<=n+2;k++){
a[j][k]-=kkk*a[i][k];
}
}
}
}
}
int main()
{
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
cin>>n;
for(int i=1;i<=n+1;++i){
for(int j=1;j<=n;j++){
cin>>num;
a[i][j]=2*num,a[i][n+2]+=num*num;
}
a[i][n+1]=1;
}
gauss();
for(int i=1;i<=n;++i){
cout<<fixed<<setprecision(3)<<a[i][n+2]<<' ';
}
return 0;
}