高斯消元: O ( n 3 ) O(n^3) O(n3)
- 写出增广矩阵,将增广矩阵通过初等行变换变成阶梯型,然后往回带
- 适用于求解包含
n
n
n个方程,
n
n
n个未知数的多元线性方程组
例如下式多元方程组:
{ a 1 , 1 ∗ x 1 + a 1 , 2 ∗ x i + ⋯ + a 1 , n ∗ x n = b 1 a 2 , 1 ∗ x 1 + a 2 , 2 ∗ x i + ⋯ + a 2 , n ∗ x n = b 2 ⋮ a n , 1 ∗ x 1 + a n , 2 ∗ x i + ⋯ + a n , n ∗ x n = b n \begin{cases} a_{1,1}*x_1 + a_{1,2}*x_i +\quad \cdots \quad+ a_{1, n}*x_n = b_1\\ a_{2,1}*x_1 + a_{2,2}*x_i +\quad \cdots \quad+ a_{2, n}*x_n = b_2 \\ \qquad \qquad \vdots \quad \\ a_{n,1}*x_1 + a_{n,2}*x_i +\quad \cdots \quad+ a_{n, n}*x_n = b_n\end{cases} ⎩⎪⎪⎪⎪⎨⎪⎪⎪⎪⎧a1,1∗x1+a1,2∗xi+⋯+a1,n∗xn=b1a2,1∗x1+a2,2∗xi+⋯+a2,n∗xn=b2⋮an,1∗x1+an,2∗xi+⋯+an,n∗xn=bn
写出其增广矩阵:
[ a 1 , 1 a 1 , 2 ⋯ a 1 , n b 1 a 2 , 1 a 2 , 2 ⋯ a 2 , n b 2 ⋮ a n , 1 a n , 2 ⋯ a n , n b n ] \begin{bmatrix} a_{1,1}&a_{1,2} \quad \cdots \quad a_{1, n} \quad b_1\\a_{2,1}&a_{2,2} \quad \cdots \quad a_{2, n} \quad b_2 \\ \qquad \qquad \vdots \quad \\ a_{n,1}&a_{n,2} \quad \cdots \quad a_{n, n} \quad b_n \end{bmatrix}\quad ⎣⎢⎢⎢⎡a1,1a2,1⋮an,1a1,2⋯a1,nb1a2,2⋯a2,nb2an,2⋯an,nbn⎦⎥⎥⎥⎤
通过初等行变换,变成阶梯型矩阵(取
n
=
4
n = 4
n=4)为例:
[
a
1
,
1
a
1
,
2
a
1
,
3
a
1
,
4
b
1
0
a
2
,
2
a
2
,
3
a
2
,
4
b
2
0
0
a
3
,
3
a
3
,
4
b
3
0
0
0
a
4
,
4
b
4
]
\begin{bmatrix} a_{1,1}&a_{1,2}& a_{1,3} &a_{1, 4} & b_1\\ 0&a_{2,2}& a_{2,3} &a_{2, 4} & b_2 \\ 0&0& a_{3,3} &a_{3, 4} & b_3 \\ 0&0&0 &a_{4, 4} & b_4 \end{bmatrix}\quad
⎣⎢⎢⎡a1,1000a1,2a2,200a1,3a2,3a3,30a1,4a2,4a3,4a4,4b1b2b3b4⎦⎥⎥⎤
高斯消元模板:
int gauss() // 浮点值
{
int c, r;
for(c = 0, r = 0; c < n; ++ c)
{
int t = r; // 找到最大行
for(int i = r + 1; i < n; ++i)
{
if(fabs(a[i][c]) > fabs(a[t][c]))
t = i;
}
if(fabs(a[t][c]) < eps) continue;
for(int i = c; i <= n; ++i) swap(a[t][i], a[r][i]); // 把最大行换上去
for(int i = n; i >= c; -- i) a[r][i] /= a[r][c]; // 把这一行第一个数变为1
for(int i = r + 1; i < n; ++i)
{
if(fabs(a[i][c]) > eps) // 不是0
{
for(int j = n; j >= c; --j)
{
a[i][j] -= a[r][j] * a[i][c];
}
}
}
r ++;
}
if(r < n) {
// 当系数全为0,常数不为0时,无解
for(int i = r; i < n; ++i)
if(fabs(a[i][n]) > eps) return 2;
return 1;
}
for(int i = n - 1; i >= 0; -- i)
{
for(int j = i + 1; j < n; ++ j)
{
a[i][n] -= a[j][n] * a[i][j];
}
}
return 0;
}
// 布尔值
// 异或性质:
// a ^ b ^ c = x, e ^ f = y.
// a ^ b ^ c ^ e ^ f = x ^ y
int gauss()
{
int c, r;
for (c = 0, r = 0; c < n; c ++ )
{
int t = r;
for (int i = r; i < n; i ++ ) // 找非零行
if (a[i][c])
t = i;
if (!a[t][c]) continue;
for (int i = c; i <= n; i ++ ) swap(a[r][i], a[t][i]); // 将非零行换到最顶端
for (int i = r + 1; i < n; i ++ ) // 用当前行将下面所有的列消成0
if (a[i][c])
for (int j = n; j >= c; j -- )
a[i][j] ^= a[r][j];
r ++ ;
}
if (r < n)
{
for (int i = r; i < n; i ++ )
if (a[i][n])
return 2; // 无解
return 1; // 有多组解
}
for (int i = n - 1; i >= 0; i -- )
for (int j = i + 1; j < n; j ++ )
a[i][n] ^= a[i][j] * a[j][n];
return 0; // 有唯一解
}
例题1(浮点型模板)
例题2(布尔型模板)
例题3(浮点型应用)
题意:
Sol:
球体上所有点到球心的距离是相等的,因次只需求出一个点
(
x
1
,
x
2
,
x
3
⋯
,
x
n
)
(x_1, x_2, x_3 \cdots, x_n)
(x1,x2,x3⋯,xn),使得:
∑
j
=
1
n
(
a
i
,
j
−
x
j
)
2
=
C
\sum_{j=1}^n(a_{i,j} - x_j)^2 = C
j=1∑n(ai,j−xj)2=C
其中:
C
C
C是常数,
i
∈
[
1
,
n
+
1
]
i \in [1, n+1]
i∈[1,n+1],球面上第
i
i
i个点的坐标为
(
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)。
该方程组由
n
+
1
n+1
n+1个
n
n
n元二次方程构成,不是线性方程组。但是,我们可以两两相减,变成
n
n
n个
n
n
n元一次方程组,同时消去了常数
C
C
C。
∑
j
=
1
n
(
a
i
,
j
2
−
a
i
+
1
,
j
2
−
2
x
j
(
a
i
,
j
−
a
i
+
1
,
j
)
)
=
0
i
∈
[
1
,
n
]
\sum_{j=1}^n (a_{i,j}^2 - a_{i+1, j}^2 - 2x_j(a_{i,j} - a_{i+1,j})) = 0 \qquad i \in[1, n]
j=1∑n(ai,j2−ai+1,j2−2xj(ai,j−ai+1,j))=0i∈[1,n]
将变量放一边,常量放一边有:
∑
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
)
i
∈
[
1
,
n
]
\sum_{j=1}^n 2(a_{i,j} - a_{i+1,j})x_j = \sum_{j=1}^n (a_{i,j}^2 - a_{i+1,j}^2) \qquad i \in [1, n]
j=1∑n2(ai,j−ai+1,j)xj=j=1∑n(ai,j2−ai+1,j2)i∈[1,n]
写成增广矩阵:
[
2
(
a
1
,
1
−
a
2
,
1
)
2
(
a
1
,
2
−
a
2
,
2
)
⋯
2
(
a
1
,
n
−
a
2
,
n
)
∑
j
=
1
n
(
a
1
,
j
2
−
a
2
,
j
2
)
2
(
a
2
,
1
−
a
3
,
1
)
2
(
a
2
,
2
−
a
3
,
2
)
⋯
2
(
a
2
,
n
−
a
3
,
n
)
∑
j
=
1
n
(
a
2
,
j
2
−
a
3
,
j
2
)
⋮
2
(
a
n
,
1
−
a
n
+
1
,
1
)
2
(
a
n
,
2
−
a
n
+
1
,
2
)
⋯
2
(
a
n
,
n
−
a
n
+
1
,
n
)
∑
j
=
1
n
(
a
n
,
j
2
−
a
n
+
1
,
j
2
)
]
\begin{bmatrix} 2(a_{1,1} - a_{2,1}) & 2(a_{1,2} - a_{2,2}) \quad \cdots \quad 2(a_{1,n} - a_{2,n}) \quad \sum_{j=1}^n (a_{1,j}^2 - a_{2,j}^2)\\ 2(a_{2,1} - a_{3,1}) & 2(a_{2,2} - a_{3,2}) \quad \cdots \quad 2(a_{2,n} - a_{3,n}) \quad \sum_{j=1}^n (a_{2,j}^2 - a_{3,j}^2)\\ \qquad \qquad \vdots \quad \\ 2(a_{n,1} - a_{n+1,1}) & 2(a_{n,2} - a_{n+1,2}) \quad \cdots \quad 2(a_{n,n} - a_{n+1,n}) \quad \sum_{j=1}^n (a_{n,j}^2 - a_{n+1,j}^2) \end{bmatrix}\quad
⎣⎢⎢⎢⎡2(a1,1−a2,1)2(a2,1−a3,1)⋮2(an,1−an+1,1)2(a1,2−a2,2)⋯2(a1,n−a2,n)∑j=1n(a1,j2−a2,j2)2(a2,2−a3,2)⋯2(a2,n−a3,n)∑j=1n(a2,j2−a3,j2)2(an,2−an+1,2)⋯2(an,n−an+1,n)∑j=1n(an,j2−an+1,j2)⎦⎥⎥⎥⎤
利用高斯消元求解
Code:
#include <bits/stdc++.h>
using namespace std;
const int N = 20;
const double eps = 1e-8;
int n;
double a[N][N], d[N][N];
int gauss()
{
int c, r;
for(r = 0, c = 0; c < n; ++ c)
{
int t = r;
for(int i = r + 1; i < n; ++i)
if(fabs(a[i][c]) > fabs(a[t][c]))
t = i;
if(fabs(a[t][c]) < eps) continue;
for(int i = c; i <= n; ++i) swap(a[t][i], a[r][i]);
for(int i = n; i >= c; -- i) a[r][i] /= a[r][c];
for(int i = r + 1; i < n; ++i)
{
if(fabs(a[i][c]) > eps)
{
for(int j = n; j >= c; -- j)
{
a[i][j] -= a[i][c] * a[r][j];
}
}
}
r ++;
}
if(r < n)
{
for(int i = r; i < n; ++i)
if(fabs(a[i][n]) > eps) return 2;
return 1;
}
for(int i = n - 1; i >= 0; -- i)
for(int j = i + 1; j < n; ++j)
a[i][n] -= a[j][n] * a[i][j];
return 0;
}
double pow2(double a, double b)
{
return a * a - b * b;
}
int main()
{
cin >> n;
for(int i = 0; i <= n; ++i)
for(int j = 0; j < n; ++j)
cin >> d[i][j];
// 增广矩阵
for(int i = 0; i < n; ++i)
for(int j = 0; j <= n; ++j)
{
if(j == n)
{
for(int k = 0; k < n; ++k)
{
a[i][j] += pow2(d[i][k], d[i + 1][k]);
}
}
else
{
a[i][j] = 2 * (d[i][j] - d[i + 1][j]);
}
}
int t = gauss();
for(int i = 0; i < n; ++i) printf("%.3f ", a[i][n]);
}