bzoj1013 [JSOI2008]球形空间产生器sphere (高斯消元)

1013  [JSOI2008]球形空间产生器sphere

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

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 )


传送门

 

事情是这样的,本来是在写另外一题,肝了半天没写出来,查了下题号发现标签是“概率DP+高斯消元”。由于姿势水平不够,并不知道这是个什么骚东西,找道题来学一下。
 
(UPD:最后还是没写出来。。。
 
高斯消元是个用于解n元线性方程组的玩意。
对于线性方程组$\begin{cases} a_1 x_1 + a_2 x_2 +a_3 x_3 = d_1\\b_1 x_1 + b_2 x_2 +b_3 x_3 = d_2\\c_1 x_1 + c_2 x_2 +c_3 x_3 = d_3 \end{cases}$
我们可以写出一个等价的系数矩阵$\begin{bmatrix}a_1&a_2&a_3\\b_1&b_2&b_3\\c_1&c_2&c_3\end{bmatrix} \times \begin{bmatrix}x_1\\x_2\\x_3\end{bmatrix} = \begin{bmatrix}d_1\\d_2\\d_3\end{bmatrix}$
而我们希望得到的是这样一个矩阵:$\begin{bmatrix}a_{11}&a_{12}&a_{13}\\0&a_{22}&a_{23}\\0&0&a_{33}\end{bmatrix} \times \begin{bmatrix}x_1\\x_2\\x_3\end{bmatrix} = \begin{bmatrix}b_1\\b_2\\b_3\end{bmatrix}$
系数矩阵的最后一行是$x_3$的解,只要逐层向上代入消元就能解出所有未知数。
具体的算法流程是这样的:
1 枚举矩阵中的元素$a_{i,i}$,
  1.1 从其下方中找到绝对值最大的元素$a_{j,i}$;
  1.2 将第$i$行与第$j$行$[i,n+1]$的部分交换;
  1.3 将第$i$列第$[i+1,n]$行调整为$0$;
2 从第$n$行至第$1$行进行消元;
 
对于这道题,距离公式带平方,但是题目给了$n+1$条式子,用后$n$条式子减去第一条式子即可消去二次项。
 1 #include<cstring>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<algorithm>
 5 #define foru(i,x,y) for(int i=x;i<=y;i++)
 6 #define ford(i,x,y) for(int i=x;i>=y;i--)
 7 using namespace std;
 8 double f[100][100],x,r[100];
 9 int n;
10 
11 void gauss(){
12     foru(i,1,n){
13         int t=i;
14         foru(j,i+1,n)if(fabs(f[j][i])>fabs(f[t][i]))t=j;
15         if(t!=i)foru(j,i,n+1)swap(f[i][j],f[t][j]);//交换 提高精度 
16         foru(j,i+1,n){
17             double x=f[j][i]/f[i][i];
18             foru(k,i,n+1)f[j][k]-=x*f[i][k];
19             //f[i][i]以下的元素用f[i][i]按比例减为0,同行的其它元素按比例减去第一行的对应值 
20             //即矩阵的初等行变换 
21         }
22     }
23     ford(i,n,1){
24         double t=(f[i][n+1]/=f[i][i]);
25         foru(j,1,i-1)f[j][n+1]-=(t*f[j][i]);//消元 
26     }
27 }
28 
29 int main(){
30     scanf("%d",&n);
31     foru(i,1,n)scanf("%lf",&r[i]);
32     foru(i,1,n){
33         foru(j,1,n){
34             scanf("%lf",&x);
35             f[i][j]=2*(x-r[j]);
36             f[i][n+1]+=x*x-r[j]*r[j];//消去二次项 
37         }
38     }
39     gauss();
40     printf("%.3lf",f[1][n+1]);
41     foru(i,2,n)printf(" %.3lf",f[i][n+1]);
42     return 0; 
43 }

 

 

posted @ 2017-06-13 13:32  羊毛羊  阅读(244)  评论(0编辑  收藏  举报