1. 程式人生 > >P4035 [JSOI2008]球形空間產生器

P4035 [JSOI2008]球形空間產生器

pro amp show 就是 () 整體 可能 必須 stream

P4035 [JSOI2008]球形空間產生器

題目

題目大意

給出n維空間上的n+1個點,且這些店都在一個圓的表面,求圈心坐標.

定義:

  1. 球心:到球面上任意一點距離都相等的點。

  2. 兩點間距離公式

\[ A(x_1,x_2,x_3,x_4,\cdots x_n) \]

\[ B(y_1,y_2,y_3,y_4,\cdots y_n) \]

\[ distance:\sqrt[2]{\sum_{i=1}^{n}(x_i-y_i)^2} \]


題目看上去應該就是解方程了。

我們可以使用gauss消元法

不過問題就來了。這是一個二次多元方程組。而我們的gauss只能解決一次。而且gauss的前提是有n個未知數,我們必須有n個方程。(當然有些不嚴謹

我們就要考慮移項和再設一個未知數

原方程中的一個:我們先設一個數,r。表示根據圓的標準方程算出來的半徑
A為一個點,R為圓心

\[A(x_1,x_2,x_3,x_4,\cdots x_n)\]

\[R(y_1,y_2,y_3,y_4,\cdots y_n)\]

\[\sum_{i=1}^{n}(x_i-y_i)^2=r^2\]

\[\sum_{i=1}^{n}x_i^2-\sum_{i=1}^{n}2x_iy_i+\sum_{i=1}^{n}y_i^2=r^2\]

請註意這裏的A的坐標都是已知量。而r和R的坐標不是

然後我們移項
\[-\sum_{i=1}^{n}2x_iy_i+(\sum_{i=1}^{n}y_i^2-r^2)=-\sum_{i=1}^{n}x_i^2\]

最繞的一步來了
我們將括號內的整體代換(或看成一個未知數)

這樣就有n+1個未知數來了。而且我們解出方程來後,我們只需要前n個未知數。後面我們後面設的未知數雖然解出來了。但是沒有什麽用。只是我們一個輔助變量

同時,這個題也告訴我們一些小技巧。

  1. 出題人不可能多給條件。有些是要我們自己設的
  2. 遇到二次方程。可以考慮拆括號和移項。然後進行還原達到降冪的目的
#include<cstdio> 
#include<algorithm>
#include<iostream>
#include<cmath>
using namespace std;
double
map[15][15]; double ans[15]; int n; void gauss() { for(int i=1;i<=n+1;i++) { int r=i; for(int j=i+1;j<=n+1;j++) if(fabs(map[r][i])<fabs(map[j][i])) r=j; if(r!=i) for(int j=i;j<=n+2;j++) swap(map[i][j],map[r][j]); double div=map[i][i]; for(int j=i;j<=n+2;j++) map[i][j]/=div; for(int j=i+1;j<=n+1;j++) { div=map[j][i]; for(int k=i;k<=n+2;k++) map[j][k]-=div*map[i][k]; } } ans[n+1]=map[n+1][n+2]; for(int i=n;i>=1;i--) { ans[i]=map[i][n+2]; for(int j=i+1;j<=n+1;j++) ans[i]-=map[i][j]*ans[j]; } } int main() { scanf("%d",&n); for(int i=1;i<=n+1;i++) { double data; for(int j=1;j<=n;j++) { scanf("%lf",&data); map[i][j]=-2.0*data; map[i][n+2]-=data*data; } map[i][n+1]=1; } gauss(); printf("%.3lf",ans[1]); for(int i=2;i<=n;i++) printf(" %.3lf",ans[i]); }

P4035 [JSOI2008]球形空間產生器