高斯消元是用来解决线性方程组的,也就是可以解决能够转换成线性方程组的题目:
n维圆心求解问题
我们知道已知 n 维球上的 n+1 个点,是可以求解 n 维球心的坐标的。
假设,已知圆上(2维球)三点:
(
a
1
,
b
1
)
,
(
a
2
,
b
2
)
,
(
a
3
,
b
3
)
(a_1,b_1),(a_2,b_2),(a_3,b_3)
(a1,b1),(a2,b2),(a3,b3)
那么我们可以得到方程组:
{
(
x
−
a
1
)
2
+
(
y
−
b
1
)
2
=
r
2
(
x
−
a
2
)
2
+
(
y
−
b
2
)
2
=
r
2
(
x
−
a
3
)
2
+
(
y
−
b
3
)
2
=
r
2
\begin{cases} (x-a_1)^2 + (y-b_1)^2 = r^2 \\(x-a_2)^2 + (y-b_2)^2 = r^2 \\(x-a_3)^2 + (y-b_3)^2 = r^2 \end{cases}
⎩⎪⎨⎪⎧(x−a1)2+(y−b1)2=r2(x−a2)2+(y−b2)2=r2(x−a3)2+(y−b3)2=r2
做一下减法转换:
{
2
(
a
1
−
a
2
)
x
+
2
(
b
1
−
b
2
)
y
=
(
a
1
2
−
a
2
2
)
+
(
b
1
2
−
b
2
2
)
2
(
a
2
−
a
3
)
x
+
2
(
b
2
−
b
3
)
y
=
(
a
2
2
−
a
3
2
)
+
(
b
2
2
−
b
3
2
)
\begin{cases} 2(a_1-a_2)x + 2(b_1-b_2)y = (a_1^2 - a_2^2) + (b_1^2 - b_2^2) \\2(a_2-a_3)x + 2(b_2-b_3)y = (a_2^2 - a_3^2) + (b_2^2 - b_3^2) \end{cases}
{2(a1−a2)x+2(b1−b2)y=(a12−a22)+(b12−b22)2(a2−a3)x+2(b2−b3)y=(a22−a32)+(b22−b32)这就是我们熟知的线性方程组了,然后就gauss就行了。
拓展到 n 维:
{
2
(
a
1
−
a
2
)
x
+
2
(
b
1
−
b
2
)
y
+
…
+
2
(
z
1
−
z
2
)
p
=
(
a
1
2
−
a
2
2
)
+
(
b
1
2
−
b
2
2
)
+
…
+
(
z
1
2
−
z
2
2
)
2
(
a
2
−
a
3
)
x
+
2
(
b
2
−
b
3
)
y
+
…
+
2
(
z
2
−
z
3
)
p
=
(
a
2
2
−
a
3
2
)
+
(
b
2
2
−
b
3
2
)
+
…
+
(
z
2
2
−
z
3
2
)
…
…
2
(
a
n
−
1
−
a
n
)
x
+
2
(
b
n
−
1
−
b
n
)
y
+
…
+
2
(
z
n
−
1
−
z
n
)
p
=
(
a
n
−
1
2
−
a
n
2
)
+
…
+
(
z
n
−
1
2
−
z
n
2
)
\begin{cases} 2(a_1-a_2)x+2(b_1-b_2)y +… + 2(z_1-z_2)p = (a_1^2 - a_2^2) + (b_1^2 - b _ 2^2)+…+(z_1^2-z_2^2) \\2(a_2-a_3)x + 2(b_2-b_3)y +… + 2(z_2-z_3)p = (a_2^2 - a_3^2) + (b_2^2 - b _ 3^2)+…+(z_2^2-z_3^2) \\…… \\2(a_{n-1}-a_n)x + 2(b_{n-1}-b_n)y +… + 2(z_{n-1}-z_n)p = (a_{n-1}^2 - a_n^2) +…+(z_{n-1}^2-z_n^2) \end{cases}
⎩⎪⎪⎪⎨⎪⎪⎪⎧2(a1−a2)x+2(b1−b2)y+…+2(z1−z2)p=(a12−a22)+(b12−b22)+…+(z12−z22)2(a2−a3)x+2(b2−b3)y+…+2(z2−z3)p=(a22−a32)+(b22−b32)+…+(z22−z32)……2(an−1−an)x+2(bn−1−bn)y+…+2(zn−1−zn)p=(an−12−an2)+…+(zn−12−zn2)
例题:球形空间产生器
有一个球形空间产生器能够在n维空间中产生一个坚硬的球体。
现在,你被困在了这个n维球体中,你只知道球面上n+1个点的坐标,你需要以最快的速度确定这个n维球体的球心坐标,以便于摧毁这个球形空间产生器。
输入格式
第一行是一个整数n。
接下来的n+1行,每行有n个实数,表示球面上一点的n维坐标。
每一个实数精确到小数点后6位,且其绝对值都不超过20000。
输出格式
有且只有一行,依次给出球心的n维坐标(n个实数),两个实数之间用一个空格隔开。
每个实数精确到小数点后3位。
数据保证有解。
数据范围
1≤n≤10
输入样例:
2
0.0 0.0
-1.0 1.0
1.0 0.0
输出样例:
0.500 1.500
#include<cstdio>
#include<iostream>
#include<string>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<vector>
#include<map>
#include<queue>
#include<utility>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
const int maxn = 110;
const int inf = 0x3f3f3f3f3f;
const double eps = 1e-7;
int n;
double a[maxn][maxn];
double b[maxn][maxn];
void gauss(){
double del;
for(int i=1;i<=n;i++){
int k=i;
for(int j=i+1;j<=n;j++){
if(fabs(a[j][i])>fabs(a[k][i]))
k=j;
}
if(fabs(del=a[k][i])<eps) continue;
if(i!=k){
for(int j=i;j<=n+1;j++)
swap(a[i][j],a[k][j]);
}
for(int j=i;j<=n+1;j++) a[i][j]/=del;
for(k=1;k<=n;k++){
if(k!=i){
del=a[k][i];
for(int j=i;j<=n+1;j++)
a[k][j] -= a[i][j]*del;
}
}
}
for(int i=1;i<=n;i++){
printf("%.3f ",a[i][n+1]/a[i][i]);
}
}
int main(void)
{
scanf("%d",&n);
for(int i=1;i<=n+1;i++){
for(int j=1;j<=n;j++){
scanf("%lf",&b[i][j]);
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
a[i][j] = 2.0*(b[i][j]-b[i+1][j]);
a[i][n+1] += (b[i][j]*b[i][j]-b[i+1][j]*b[i+1][j]);
}
}
gauss();
return 0;
}