【学习笔记】高斯消元
说在前面:
高斯消元看上去是一个很复杂的东西,但是其实只要是理解了就会发现也就那样的
算法功能:
解方程组。
没错就是如此的简单,就是去解方程组。但是高斯消元一般是用来解决含有上百个未知数的方程组。
其时间复杂度为
算法详解:
下面我就来介绍一下高斯消元的最简单的应用,也就是解正常的一次方程组。
比如我们有以下的方程组:
在高斯消元的过程中我们会将它转化为一个矩阵,矩阵里第 行代表第 个式子,第 列代表第 个未知数的系数,其中第 也就是最后一列,代表常数项,也就是等于号后面的数
那么以上的这个方程组就会被写为:
这个时候可能会很懵,但是一定要静下心来仔细看看这个矩阵和上面的方程组
我们高斯消元的思想就是加减消元,就是我们在小学会学习到的那个知识
加减消元的解释:(如果会了就请跳过,避免看了之后有点晕)
比如我们有以下一个二元一次方程组:
那么如何进行加减消元呢?
我们考虑先消掉
很简单:
这样就能得到
我们就成功地将 这个未知数消掉了,接下来就只剩下了一个未知数,很明显就可以直接算出来 ,然后将这个值带回去,就能解出
我们在高斯消元中,就是用加减消元,从第一个未知数开始一个一个地消,直到消到只剩下一个未知数就能很轻松地能将方程解出来
按我的代码习惯而言,就是将每一个式子都消掉只剩一个未知数,这样 个式子每个式子对应一个未知数就很好地能解出来
代码详解:
下面先放代码,根据代码一点点来解释
点击查看代码
#include<bits/stdc++.h>
using namespace std;
double a[105][105];
int n;
bool Gauss(){
for(int i=1; i<=n; i++){ //第几个未知数/第几列
int mx = i; //先让最大值为 i;
for(int j = i+1; j<=n; j++){ //找到第 i 列上绝对值最大的那个数在第几行
//前 i-1 行已经有了自己的位置,就是自己有独特的保留的未知数了,再次将他设为 i 需要的值
//那么它本身的那个数就没了
if(fabs(a[j][i]) > fabs(a[mx][i])){
mx = j;
}
}
//我们认为第 i 行就是仅包含第 i 个未知数的那一行
if(mx != i){ //交换两行,需要全部交换
for(int j=1; j<=n+1; j++){
swap(a[i][j],a[mx][j]);
}
}
if(!a[i][i]){ //这一列都是 0 ,所以说这一列对未知数没有限制,也就是有可以任意取值的未知数
printf("No Solution");
return false;
}
for(int j=1; j<=n; j++){
if(j != i){
double tmp = a[j][i] / a[i][i]; //代表要减多少倍才能将这一行的第 i 个未知数消掉,因为要减一起减,所以就全部减了
for(int k = i; k<=n+1; k++){
//因为前 i 列已经被之前消没了,就全是 0 了
a[j][k] -= a[i][k] * tmp;
}
}
}
}
return true;
}
int main(){
cin>>n;
for(int i=1; i<=n; i++){
for(int j=1; j<=n+1; j++){
cin>>a[i][j];
}
}
if(Gauss()){
for(int i=1; i<=n; i++){
printf("%.2f\n",a[i][n + 1] / a[i][i]);
}
}
return 0;
}
我们就顺着代码一点点来看,这里的高斯消元部分也就是那个 函数(可能有点长,但是耐心读一读应该会有所收获)
首先最外层循环,枚举当前消到了哪一个未知数,也就是该消哪一个了。
注意我上文的解释,既然枚举到了这一个未知数,那么按照我的码风来说,前 个未知数是都被消没了的,因为如果没有消没,就不可能再将后面的式子都化为只含有一个未知数的式子
然后就继续往下看。
下面的这个 循环就是在寻找当前未知数中绝对值最大的是谁在哪一个式子里,然后我们就要将别的式子通过加减我们找到的这个式子,来将当前的未知数消掉。
而且我们默认有一点:第 个式子其最后只含有第 个未知数,所以我们的 是从 开始枚举,一开始第 行被认为是最大的一行,也相当于枚举了,也就有了下面的 里面的交换操作。
注意对于交换完了之后第 个式子就是我们找到的当前未知数绝对值最大的一个式子,那么第 行的第 列,也就是第 个未知数绝对值最大的那个数
继续最后的一个循环,就是用第 行的这个式子去消其他的式子,也就是将其他行的第 个未知数消去,让他们的系数全都变成
其他的不用我多说,我代码里写的也很清楚,也很简单,重点在于 的范围 ,是不是有种很懵的感觉
不着急,我们一点点看,先看左边界 ,因为我们消元就是将除了第 个式子之外的所有式子中含有的未知数 的系数全部变成 ,那么就意味着当我们枚举到 的时候前 个未知数,也就是前 行,一定都被全消成 了,那么此时我们再去枚举这些本来就是 的地方,想让他变成 也就没有任何意义了。
再来看右边界 ,我们考虑第 列存的是什么,存的是不是就是我们的常数项啊,在我们加减消元的过程中常数项也是需要加减的,因为这样才会满足等式的性质,等于号才不变
如果有感觉我哪里解释的不对或者不清楚,欢迎给我留言
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具