高斯消元
高斯消元
本文转自 Acwing题解板块
- 通过初等行变换把增广矩阵化为阶梯型矩阵,并回代得到方程的解
- 适用于求解 包含\(n\) 个方程,\(n\) 个未知数的多元线性方程组
例如方程组:
\[\left\{
\begin{array}{}
&a_{11}x_1+&a_{12}x_2+\cdots+&a_{1n}x_n=&b_1 \\
&a_{21}x_1+&a_{22}x_2+\cdots+&a_{2n}x_n=&b_2 \\
&\vdots&\vdots&\vdots&\vdots \\
&a_{n1}x_1+&a_{n2}x_2+\cdots+&a_{nn}x_n=&b_n \\
\end{array}
\right.
\]
增广矩阵为:
\[\begin{pmatrix}{}
a_{11}&a_{12}&\cdots&a_{1n}&b_1 \\
a_{21}&a_{22}&\cdots&a_{2n}&b_2 \\
\vdots&\vdots&\vdots&\vdots&\vdots \\
a_{n1}&a_{n2}&\cdots&a_{nn}&b_n\\
\end{pmatrix}
\]
- 接下来所有的操作都使用增广矩阵代替原方程组
前置知识:初等行(列)变换
1.把某一行乘一个非\(0\)的数 (方程的两边同时乘上一个非\(0\)数不改变方程的解)
2.交换某两行(交换两个方程位置)
3.把某一行的若干倍加到某一行上去(把某一个方程的若干倍加到另一个方程上去)
接下来,利用初等行变化,把增广矩阵化为阶梯型矩阵
阶梯型矩阵:
\[\begin{pmatrix}{}
a_{11}&a_{12}&\cdots&a_{1n}&b_1 \\
&a_{22}&\cdots&a_{2n}&b_2 \\
&&&\vdots&\vdots \\
&&&a_{nn}&b_n\\
\end{pmatrix}
\]
最后再把阶梯型矩阵从下到上回代到第一层即可得到方程的解
算法步骤
枚举每一列c
- 找到当前这一列绝对值最大的数所在的行.
- 用行变换(2)把这一行换到最上面(未确定阶梯型的行,并不是第一行).
- 用初等行变换(1) 将该行的第一个数变成 \(1\) (其余所有的数字依次跟着变化).
- 用初等行变换(3) 将下面所有行的当且列的值变成 \(0\).
模板题:Acwing.883
#include <algorithm>
#include <iostream>
#include <cstring>
#include <string>
#include <cstdio>
#include <vector>
#include <queue>
#include <cmath>
#include <map>
#include <set>
#define fi first
#define se second
#define rep(i,n) for(int i=0;i<(n);++i)
#define repA(i,a,n) for(int i=a;i<=(n);++i)
#define repD(i,a,n) for(int i=a;i>=(n);--i)
using namespace std;
using LL = long long;
const int N = 110;
const double eps = 1e-6;
double a[N][N];
int n;
int gauss()
{
int c, r;
for (c = 0, r = 0; c < n; ++ c)
{
// 找到当前这一列最大的数所在的行,把它与r行进行交换
int t = r;
for (int i = r; i < n; ++ i)
{
if (fabs(a[i][c]) > fabs(a[t][c]))
t = i;
}
//都为0,就没必要交换
if (fabs(a[t][c]) < eps) continue;
for (int i = c; i <= n; ++ i) swap(a[t][i], a[r][i]);
//把当前行对应的阶梯数变为1
for (int i = n; i >= c; --i) a[r][i] /= a[r][c];
//把阶梯数这一列下面的数字都变为0
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[r][j] * a[i][c];
r ++;//当前行已变为阶梯行,接着处理下一行
}
if (r < n)
{
// 因为已经是阶梯型,所以 r ~ n-1 的值应该都为 0
for (int i = r; i < n; ++ i)
if (fabs(a[i][n]) > eps) return 2;
return 1;// 否则, 0 = 0,就是r ~ n-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;
}
int main()
{
// ios::sync_with_stdio(0);
// cin.tie(0);
// cout.tie(0);
cin >> n;
rep(i, n)
repA(j, 0, n)
cin >> a[i][j];
int t = gauss();
if (t == 0)
{
rep(i, n) printf("%.2f\n", a[i][n]);
}
else if (t == 1) puts("Infinite group solutions");
else puts("No solution");
return 0;
}
高斯消元解异或线性方程组:Acwing.884
同上一题一样,异或是不进位的加法,把上面的模板的加法用异或替代即可。
#include <algorithm>
#include <iostream>
#include <cstring>
#include <string>
#include <cstdio>
#include <vector>
#include <queue>
#include <cmath>
#include <map>
#include <set>
#define fi first
#define se second
#define rep(i,n) for(int i=0;i<(n);++i)
#define repA(i,a,n) for(int i=a;i<=(n);++i)
#define repD(i,a,n) for(int i=a;i>=(n);--i)
using namespace std;
using LL = long long;
const int N = 110;
int a[N][N];
int n;
int gauss()
{
int c, r;
for (c = 0, r = 0; c < n; ++ c)
{
// 找到当前这一列最大的数所在的行,把它与r行进行交换
int t = r;
for (int i = r; i < n; ++ i)
{
if (a[i][c])
{
t = i;
break;
}
}
//都为0,就没必要交换
if (a[t][c] == 0) continue;
for (int i = c; i <= n; ++ i) swap(a[t][i], a[r][i]);
//把阶梯树这一列下面的数字都变为0
for (int i = r + 1; i < n; ++ i)
if (a[i][c])
for (int j = n; j >= c; -- j)
a[i][j] ^= a[r][j];
r ++;//当前行已变为阶梯行,接着处理下一行
}
if (r < n)
{
// 因为已经是阶梯型,所以 r ~ n-1 的值应该都为 0
for (int i = r; i < n; ++ i)
if (a[i][n]) return 2;
return 1;// 否则, 0 = 0,就是r ~ n-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;
}
int main()
{
// ios::sync_with_stdio(0);
// cin.tie(0);
// cout.tie(0);
cin >> n;
rep(i, n)
repA(j, 0, n)
cin >> a[i][j];
int t = gauss();
if (t == 0)
{
rep(i, n) printf("%d\n", a[i][n]);
}
else if (t == 1) puts("Multiple sets of solutions");
else puts("No solution");
return 0;
}

浙公网安备 33010602011771号