浅谈高斯消元
线性代数相关定义
线型方程组
设有
其中
当常数项
当
称为
对于
齐次线性方程组一定有零解,不一定有非零解。
矩阵
对于非齐次线性方程组
有如下几个矩阵:
其中
矩阵的初等变换
下面三种变换称为矩阵的初等行变换:
- 对换两行(对换
两行,记作 ) - 以非零数
乘上某一行中所有元(第 行乘以 ,记作 ) - 把某一行数所有元的
倍加到另一行的所有元上去(第 行的 倍加到第 行上,记作 )
把矩阵的初等行变换的“行”换成“列”,就得到了矩阵的初等列变换。
矩阵的初等行变换和矩阵的初等列变换,统称为初等变换。
高斯消元
主要思想
反复运用初等变换将原矩阵变换为形如
的上三角矩阵,然后从下至上回带求解。
而且可以观察到每一行对应主元之下,该主元的系数都为
主要步骤
- 找到当前主元系数不为
的一行(这里通常也找系数绝对值较大的一行)。 - 将这一行与当前处理到的行交换。
- 运用初等变换将主元的系数变为
。 - 运用初等变换将其余行(不包含当前行上面的行)的主元的系数变为
(目的是变成上三角矩阵)。
最后通过上三角矩阵回带求解,得到答案。
无解 & 无穷解
通过初中知识可知,
- 无解,出现
时。 - 无穷解,出现
时。
故处理时如果出现找不到主元时先跳过这一行,最后在所有系数都为
无解举例
此时无解。
无穷解举例
此时有无数解。
解释
下面通过几组样例,在程序中插入 printf
语句,追踪一下高斯消元的执行过程。
唯一解
输入:
3
2 -1 1 1
4 1 -1 5
1 1 1 0
输出:
x1=1.00
x2=0.00
x3=-1.00
无穷解
输入:
4
0 0 2 4 6
0 0 1 1 2
0 0 4 8 12
1 1 1 1 0
输出:
0
无解
输入:
4
0 0 2 1 2
0 0 1 1 1
0 0 0 1 1
0 0 0 0 0
输出:
-1
代码实现
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <ctime>
using namespace std;
const int maxn = 105;
const double eps = 1e-7;//精度
double a[maxn][maxn];
double ans[maxn];
int n;
void print()
{
puts("");
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n + 1; j++) cout << a[i][j] << " ";
puts("");
}
puts("");
}//调试,输出矩阵
void gauss()
{
//row 行 col 列
int col = 1, row = 1;
for (col = 1; col <= n; col++)//枚举主元所在列(1~n)
{
//step1 找到主元非0的一行
int t = row;
for (int i = row; i <= n; i++)
{
if (fabs(a[i][col]) > eps)
{
t = i;
break;
}
}
// step2
if (fabs(a[t][col]) < eps) continue;//主元系数为0,即产生了自由元,先暂且不管
swap(a[row], a[t]);//否则替换两行
//step3 将主元系数置1,注意枚举顺序
for (int i = n + 1; i >= row; i--)
{
a[row][i] /= a[row][col];
}
//step4 将下面所有的主元系数消为0
for (int i = row + 1; i <= n; i++)
{
for (int j = n + 1; j >= col; j--)
{
a[i][j] -= a[i][col] * a[row][j];
}
}
//step5 处理下一个主元
row++;
}
//处理的主元个数小于n,产生了自由元,一定是无解/无穷解
if (row <= n)
{
for (int i = row; i <= n; i++)
{
if (fabs(a[i][n + 1]) > eps)
{
cout << "-1" << endl;
exit(0);
}
}
puts("0");
exit(0);
return;
}
else
{
//step6 回代求解答案
for (int i = n; i >= 1; i--)
{
ans[i] = a[i][n + 1];
for (int j = i + 1; j <= n; j++)
{
ans[i] -= ans[j] * a[i][j];
}
}
for (int i = 1; i <= n; i++) printf("x%d=%.2lf\n", i, ans[i]);
}
}
int main()
{
#ifndef ONLINE_JUDGE
#define LOCAL
//freopen("in.txt","r",stdin);
#endif
cin >> n;
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n + 1; j++)
{
scanf("%lf", &a[i][j]);
}
}
gauss();
#ifdef LOCAL
fprintf(stderr, "%f\n", 1.0 * clock() / CLOCKS_PER_SEC);
#endif
return 0;
}
高斯-约当消元法
主要思想
与高斯消元思想相近,但略有不同。
反复运用初等变换将系数矩阵变换为形如
的单位矩阵。
主要步骤
- 找到当前主元系数不为
的一行(这里通常也找系数绝对值较大的一行)。 - 将这一行与当前处理到的行交换。
- 运用初等变换将主元的系数变为
。 - 运用初等变换将其余行的主元的系数变为
。
解释
追踪高斯-约当消元的执行过程。
输入:
3
1 3 4 5
1 4 7 3
9 3 2 2
输出
-0.97
5.18
-2.39
代码实现
相比高斯消元只需改动一点,具体细节见代码。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <ctime>
using namespace std;
const int maxn = 105;
const double eps = 1e-7;//精度
double a[maxn][maxn];
double ans[maxn];
int n;
void print()
{
puts("");
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n + 1; j++) cout << a[i][j] << " ";
puts("");
}
puts("");
}//调试,输出矩阵
void gauss()
{
//row 行 col 列
int col = 1, row = 1;
for (col = 1; col <= n; col++)//枚举主元所在列(1~n)
{
//step1 找到主元非0的一行
int t = row;
for (int i = row; i <= n; i++)
{
if (fabs(a[i][col]) > eps)
{
t = i;
break;
}
}
// step2
if (fabs(a[t][col]) < eps) continue;//主元系数为0,即产生了自由元,先暂且不管
swap(a[row], a[t]);//否则替换两行
//step3 将主元系数置1,注意枚举顺序
for (int i = n + 1; i >= row; i--)
{
a[row][i] /= a[row][col];
}
//step4 将所有的主元系数消为0
for (int i = 1; i <= n; i++)
{
if (i == row) continue;
for (int j = n + 1; j >= col; j--)
{
a[i][j] -= a[i][col] * a[row][j];
}
}
//cout<<row<<" "<<col<<endl;
//print();
//step5 处理下一个主元
row++;
}
//处理的主元个数小于n,产生了自由元,一定是无解/无穷解
if (row <= n)
{
for (int i = row; i <= n; i++)
{
if (fabs(a[i][n + 1]) > eps)
{
cout << "No Solution" << endl;
exit(0);
}
}
puts("No Solution");
exit(0);
return;
}
else
{
//step6 输出答案
for (int i = 1; i <= n; i++) printf("%.2lf\n", a[i][n + 1]);
}
}
int main()
{
#ifndef ONLINE_JUDGE
#define LOCAL
//freopen("in.txt","r",stdin);
#endif
cin >> n;
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n + 1; j++)
{
scanf("%lf", &a[i][j]);
}
}
gauss();
puts("");
#ifdef LOCAL
fprintf(stderr, "%f\n", 1.0 * clock() / CLOCKS_PER_SEC);
#endif
return 0;
}
例题
本文作者:vanueber
本文链接:https://www.cnblogs.com/vanueber/p/18669234
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步