高斯消元
首先给出几个提示:
-
n
n
n维空间中两点距离为:
∑ i = 1 n ( x 1 , i − x 2 , i ) 2 \sqrt{\sum\limits_{i=1}^{n}(x_{1,i}-x_{2,i})^2} i=1∑n(x1,i−x2,i)2 - 球心是什么?
就是到球面上任意一点的距离都相等的点 - 在 n n n维空间中,知道一个点与 n + 1 n+1 n+1个点的距离,就可以确定这个点的坐标
知道这么多就够了。
因为定理1、2,所以设点
a
i
a_i
ai坐标为
(
a
i
,
1
,
a
i
,
2
,
⋯
a
i
,
n
)
(a_{i,1},a_{i,2},\cdots a_{i,n})
(ai,1,ai,2,⋯ai,n),圆心为点
x
x
x,则有
对
于
∀
i
∈
[
1
,
n
]
,
∑
j
=
1
n
(
a
i
,
j
−
x
j
)
2
=
c
对于\forall i\in[1,n],\sum\limits_{j=1}^{n}(a_{i,j}-x_j)^2=c
对于∀i∈[1,n],j=1∑n(ai,j−xj)2=c
这就麻烦了:怎么把它转化为高斯消元可以解决的形式?
我们把它拆开来:
∑
j
=
1
n
a
i
,
j
2
−
2
a
i
,
j
x
j
+
x
j
2
=
c
\sum\limits_{j=1}^{n}a_{i,j}^2-2a_{i,j}x_j+x_j^2=c
j=1∑nai,j2−2ai,jxj+xj2=c
我们将相邻两个式子做差
可以得到
∑
j
=
1
n
a
i
,
j
2
−
a
i
−
1
,
j
2
−
2
(
a
i
,
j
x
j
−
a
i
−
1
,
j
x
j
)
=
0
\sum\limits_{j=1}^{n}a_{i,j}^2-a_{i-1,j}^2-2(a_{i,j}x_j-a_{i-1,j}x_j)=0
j=1∑nai,j2−ai−1,j2−2(ai,jxj−ai−1,jxj)=0
将常数项和一次项分别放到等号两边:
∑
j
=
1
n
2
(
a
i
,
j
−
a
i
−
1
,
j
)
x
j
=
∑
j
=
1
n
a
i
,
j
2
−
a
i
−
1
,
j
2
\sum\limits_{j=1}^{n}2(a_{i,j}-a_{i-1,j})x_j=\sum\limits_{j=1}^{n}a_{i,j}^2-a_{i-1,j}^2
j=1∑n2(ai,j−ai−1,j)xj=j=1∑nai,j2−ai−1,j2
这不就是啦?
代码如下:
#include<cstdio>
#define sqr(x) ((x)*(x))
using namespace std;
double v[12][11],a[11][11],b[11],ans[11];
void gauss(double a[11][11],int n,double b[],double ans[])
{
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++)
{
double tmp=a[j][i]/a[i][i];
for(int k=i;k<=n;k++)
a[j][k]-=a[i][k]*tmp;
b[j]-=b[i]*tmp;
}
for(int i=n;i;i--)
{
ans[i]=b[i]/a[i][i];
for(int j=1;j<i;j++)
b[j]-=a[j][i]*ans[i];
}
}
int main()
{
int n;scanf("%d",&n);
for(int i=1;i<=n+1;i++)
for(int j=1;j<=n;j++)
scanf("%lf",v[i]+j);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
a[i][j]=2*(v[i+1][j]-v[i][j]);
b[i]+=sqr(v[i+1][j])-sqr(v[i][j]);
}
}
gauss(a,n,b,ans);
for(int i=1;i<=n;i++)
printf("%.3lf ",ans[i]);
return 0;
}