P4035 [JSOI2008]球形空间产生器
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
0.0 0.0
-1.0 1.0
1.0 0.0
Sample Output
0.500 1.500
HINT
提示:给出两个定义:1、 球心:到球面上任意一点距离都相等的点。2、 距离:设两个n为空间上的点A, B
的坐标为(a1, a2, …, an), (b1, b2, …, bn),则AB的距离定义为:dist = sqrt( (a1-b1)^2 + (a2-b2)^2 +
… + (an-bn)^2 )
sol:赤裸裸的板子题+水题
把距离公式中的平方公式拆开来,很容易得到一组n个未知数,n个方程的方程组,直接高斯消元爆出来就是答案了
#include <bits/stdc++.h> using namespace std; typedef int ll; inline ll read() { ll s=0; bool f=0; char ch=' '; while(!isdigit(ch)) { f|=(ch=='-'); ch=getchar(); } while(isdigit(ch)) { s=(s<<3)+(s<<1)+(ch^48); ch=getchar(); } return (f)?(-s):(s); } #define R(x) x=read() inline void write(ll x) { if(x<0) { putchar('-'); x=-x; } if(x<10) { putchar(x+'0'); return; } write(x/10); putchar((x%10)+'0'); return; } #define W(x) write(x),putchar(' ') #define Wl(x) write(x),putchar(' ') const int N=105; int n; double P[N][N],a[N][N],b[N]; inline void Debug() { int i,j; for(i=1;i<=n;i++) { for(j=1;j<=n;j++) printf("%.2lf ",a[i][j]); printf("%.2lf ",b[i]); } } inline void Gauss(int n) { int i,j,k; double Div; for(i=1;i<=n;i++) { int Pos=i; for(j=i+1;j<=n;j++) if(fabs(a[Pos][i])<fabs(a[j][i])) Pos=j; if(Pos!=i) { swap(a[Pos],a[i]); swap(b[Pos],b[i]); } Div=a[i][i]; for(j=i;j<=n;j++) a[i][j]/=Div; b[i]/=Div; for(j=1;j<=n;j++) if(j!=i) { Div=a[j][i]; for(k=i;k<=n;k++) { a[j][k]-=Div*a[i][k]; } b[j]-=Div*b[i]; } } } int main() { int i,j,k; R(n); for(i=1;i<=n+1;i++) { for(j=1;j<=n;j++) scanf("%lf",&P[i][j]); } for(i=1;i<=n;i++) { for(j=1;j<=n;j++) { a[i][j]=-1.*2.*(P[i][j]-P[i+1][j]); b[i]+=P[i+1][j]*P[i+1][j]-P[i][j]*P[i][j]; } } // Debug(); Gauss(n); for(i=1;i<=n;i++) printf("%.3lf ",b[i]); return 0; } /* input 2 0.0 0.0 -1.0 1.0 1.0 0.0 output 0.500 1.500 */