高斯消元法
前置数学知识
n元线性方程是具有如下形式的方程:
a
1
x
1
+
a
2
x
2
+
a
3
x
3
+
…
+
a
n
x
n
=
b
a_1x_1+a_2x_2+a_3x_3+…+a_nx_n = b
a1x1+a2x2+a3x3+…+anxn=b
其中,
a
1
,
a
2
,
.
.
.
a_1,a_2,...
a1,a2,...以及常数项
b
b
b均为已知的实数或者复数;
x
1
,
x
2
,
.
.
.
x
n
x_1,x_2,...x_n
x1,x2,...xn是未知变量。
n
n
n为正整数。
同理,一个
n
n
n元线性方程组就是由多个
n
n
n元线性方程组成的。一个含m个方程的n元线性方程组形如:
{
a
11
x
1
+
a
12
x
2
+
.
.
.
+
a
1
n
x
n
=
b
1
a
21
x
1
+
a
22
x
2
+
.
.
.
+
a
2
n
x
n
=
b
2
.
.
.
a
m
1
x
1
+
a
m
2
x
2
+
.
.
.
+
a
m
n
x
n
=
b
n
\left\{ \begin{matrix} a_{11}x_1+a_{12}x_2+...+a_{1n}x_n = b_1 \\ a_{21}x_1+a_{22}x_2+...+a_{2n}x_n = b_2\\ ...\\ a_{m1}x_1+a_{m2}x_2+...+a_{mn}x_n = b_n\\ \end{matrix} \right.
⎩
⎨
⎧a11x1+a12x2+...+a1nxn=b1a21x1+a22x2+...+a2nxn=b2...am1x1+am2x2+...+amnxn=bn
其中,
a
i
j
a_{ij}
aij和
b
i
b_i
bi都是已知的数,我们称上诉方程组为
m
×
n
m\times n
m×n线性方程组。
当
b
i
b_i
bi全为
0
0
0时,称上诉线性方程组为齐次线性方程组。
当
b
i
b_i
bi不全为
0
0
0时,称上诉线性方程组为非齐次线性方程组。
线性方程组的解有三种情况:(1)无解,(2)有唯一解,(3)有无穷多个解。如果一个线性方程组有唯一解或无穷多个解,则称它是相容的,如果无解则称它是不相容的。
高斯消元中的实现(线性代数部分)还涉及到矩阵相关的知识,这里也补充一下:
由
m
×
n
m\times n
m×n个(实或复)数
a
i
j
(
i
=
1
,
2
,
.
.
.
,
m
;
j
=
1
,
2
,
.
.
.
,
n
)
a_{ij}(i = 1,2,...,m;j = 1,2,...,n)
aij(i=1,2,...,m;j=1,2,...,n)排成
m
m
m行
n
n
n列的数表
[
a
11
a
12
⋯
a
1
n
a
21
a
22
⋯
a
2
n
⋮
⋮
⋱
⋮
a
m
1
a
m
2
⋯
a
m
n
]
\begin{bmatrix} {a_{11}}&{a_{12}}&{\cdots}&{a_{1n}}\\ {a_{21}}&{a_{22}}&{\cdots}&{a_{2n}}\\ {\vdots}&{\vdots}&{\ddots}&{\vdots}\\ {a_{m1}}&{a_{m2}}&{\cdots}&{a_{mn}}\\ \end{bmatrix}
a11a21⋮am1a12a22⋮am2⋯⋯⋱⋯a1na2n⋮amn
称为
m
m
m行
n
n
n列矩阵(或
m
×
n
m\times n
m×n矩阵),简称矩阵。数
a
i
j
a_{ij}
aij称为矩阵的第
i
i
i行第
j
j
j列的元素。
一个线性方程组中每个变量的系数以及常数项按照它们在方程组中的位置构成的矩阵,称为方程组的增广矩阵。利用矩阵记号,我们可以简化求解线性方程组。
来个例子引入一下
{
x
1
−
2
x
2
+
x
3
=
0
2
x
2
+
x
3
=
7
2
x
1
+
x
2
−
x
3
=
1
\left\{ \begin{matrix} x_1-2x_2+x_3 = 0 \\ 2x_2+x_3 = 7\\ 2x_1+x_2-x_3 = 1\\ \end{matrix} \right.
⎩
⎨
⎧x1−2x2+x3=02x2+x3=72x1+x2−x3=1
我们采用增广矩阵来记录对应的每次消元
原增广矩阵:
[
1
−
2
1
0
0
2
1
7
2
1
−
1
1
]
\begin{bmatrix} {1}&{-2}&{1}&{0}\\ {0}&{2}&{1}&{7}\\ {2}&{1}&{-1}&{1}\\ \end{bmatrix}
102−22111−1071
保留第一个方程中的
x
1
x_1
x1,并且消去其余方程中的
x
1
x_1
x1
[
1
−
2
1
0
0
2
1
7
0
5
−
3
1
]
\begin{bmatrix} {1}&{-2}&{1}&{0}\\ {0}&{2}&{1}&{7}\\ {0}&{5}&{-3}&{1}\\ \end{bmatrix}
100−22511−3071
保留第二个方程中的
x
2
x_2
x2,并且消去其余方程中的
x
2
x_2
x2
[
1
0
2
7
0
2
1
7
0
0
−
11
2
−
33
2
]
\begin{bmatrix} {1}&{0}&{2}&{7}\\ {0}&{2}&{1}&{7}\\ {0}&{0}&{-\frac{11}{2}}&{-\frac{33}{2}}\\ \end{bmatrix}
10002021−21177−233
保留第三个方程中的
x
3
x_3
x3,并且消去其余方程中的
x
3
x_3
x3,(同时将第三个方程的
x
3
x_3
x3的系数化为
1
1
1)
[
1
0
0
1
0
2
0
4
0
0
1
3
]
\begin{bmatrix} {1}&{0}&{0}&{1}\\ {0}&{2}&{0}&{4}\\ {0}&{0}&{1}&{3}\\ \end{bmatrix}
100020001143
整理一下变成
[
1
0
0
1
0
1
0
2
0
0
1
3
]
\begin{bmatrix} {1}&{0}&{0}&{1}\\ {0}&{1}&{0}&{2}\\ {0}&{0}&{1}&{3}\\ \end{bmatrix}
100010001123
所以最后方程组的解为
{
x
1
=
1
x
2
=
2
x
3
=
3
\left\{ \begin{matrix} x_1 = 1 \\ x_2 = 2\\ x_3 = 3\\ \end{matrix} \right.
⎩
⎨
⎧x1=1x2=2x3=3
其实,上诉所用的方法就叫高斯消元法,这里运用了初等行变换。
代码实现
有一点不一样的是,这个代码最后反代时用了类似递推的思想(从后往前计算答案)
#include<bits/stdc++.h>
#define re register
#define maxn 105
#define eps 1e-6
using namespace std;
int n;
double a[maxn][maxn],ans[maxn];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n;
for(re int i = 1;i <= n;i++)
for(re int j = 1;j <= n+1;j++)
cin >> a[i][j];
for(re int i = 1;i <= n;i++)
{
int r = i;
for(re int j = i+1;j <= n;j++)
if(fabs(a[r][i]) < fabs(a[j][i]))r = j;
if(fabs(a[r][i]) < eps)
{
cout << "No Solution" << '\n';
return 0;
}
if(r != i)swap(a[r],a[i]);
double div = a[i][i];
for(re int j = i;j <= n+1;j++)
a[i][j] = a[i][j]/div;
for(re int j = i+1;j <= n;j++)
{
div = a[j][i];
for(re int k = i;k <= n+1;k++)
a[j][k] = a[j][k]-a[i][k]*div;
}
}
ans[n] = a[n][n+1];
for(re int i = n-1;i >= 1;i--)
{
ans[i] = a[i][n+1];
for(re int j = i+1;j <= n;j++)
ans[i] = ans[i]-a[i][j]*ans[j];
}
for(re int i = 1;i <= n;i++)
cout << fixed << setprecision(2) << ans[i] << '\n';
return 0;
}