高斯消元法及其C++实现
深入浅出高斯消元法及其C++实现
本文章代码由博主编写但是文章由ChatGPT-o1-mini生成
博客食用更佳
在计算机算法竞赛中,线性方程组的求解是一个常见且基础的问题。高斯消元法作为一种经典的算法,因其高效和直观的特性,广泛应用于各种编程竞赛和实际问题中。本文将通过一个具体的C++实现,深入浅出地讲解高斯消元法的核心概念、实现细节以及如何应对实际编程中的挑战。
一、问题背景
高斯消元法(Gaussian Elimination)是一种用于求解线性方程组的算法。给定一个由 n n n个方程组成的线性方程组,每个方程包含 n n n个未知数,我们希望通过高斯消元法找到这些未知数的解。
题目描述
我们需要编写一个程序,输入一个 n × ( n + 1 ) n \times (n+1) n×(n+1)的矩阵,其中前 n n n列代表方程组的系数,最后一列代表常数项。程序需要输出方程组的唯一解,如果方程组无解或有无穷多解,则输出No Solution。
输入输出示例
输入示例:
3
1 3 4 5
1 4 7 3
9 3 2 2
输出示例:
-0.97
5.18
-2.39
二、高斯消元法基础
1. 基本思想
高斯消元法通过一系列行变换,将原始的线性方程组转化为上三角矩阵形式。具体步骤如下:
- 选主元(Pivoting): 对于每一列,选择绝对值最大的元素作为主元,以提高数值稳定性。
- 消元(Elimination): 利用主元,将其下方所有元素归零。
- 回代(Back Substitution): 从上到下求解未知数。
2. 处理特殊情况
在实际应用中,可能会遇到以下几种情况:
- 无解: 方程组中出现矛盾,如 0 x + 0 y + 0 z = 1 0x + 0y + 0z = 1 0x+0y+0z=1。
- 有无穷多解: 自由变量存在,方程组没有唯一解。
- 唯一解: 每个未知数都有确定的值。
三、C++实现解析
让我们逐步解析提供的C++代码,理解高斯消元法在代码中的具体实现。
1. 代码结构概述
#include <cmath>
#include <cstdint>
#include <iomanip>
#include <ios>
#include <iostream>
#include <utility>using ll = int64_t;template<class T>
T read(){T t;std::cin>>t;return t;
}constexpr ll maxn = 100;
ll n;
double im[maxn+5][maxn+5], tmp[maxn+5];void cp(double*f,double*t){for(ll i=1;i<=n+1;i++){t[i]=f[i];}
}void sp(double*f,double*t){for(ll i=1;i<=n+1;i++){std::swap(f[i],t[i]);}
}int main(){std::cin>>n;for(ll i=1;i<=n;i++){for(ll j=1;j<=n+1;j++){std::cin>>im[i][j];}}for(ll i=1;i<=n;i++){for(ll k=i;k<=n;k++){if(im[k][i]!=0){if(k!=i){sp(im[k],im[i]);}break;}}double fact = im[i][i];for(ll j=1;j<=n+1;j++){im[i][j]/=fact;}for(ll k=1;k<=n;k++){if(k==i)continue;double fact = im[k][i];for(ll j=1;j<=n+1;j++){im[k][j]-=fact*im[i][j];}}}if([]()->bool{for(ll i=1;i<=n;i++){bool isAllZero=true;for(ll j=1;j<=n;j++){if(im[i][j]!=0){isAllZero=false;}}if(isAllZero){return false;}}for(ll i=1;i<=n;i++){if(std::isnan(im[i][n+1])){return false;}}return true;}()){std::cout<<std::fixed<<std::setprecision(2);for(ll i=1;i<=n;i++){std::cout<<im[i][n+1]<<'\n';}}else{std::cout<<"No Solution\n";}
}
2. 代码详解
2.1 数据输入
std::cin>>n;
for(ll i=1;i<=n;i++){for(ll j=1;j<=n+1;j++){std::cin>>im[i][j];}
}
- 首先读取方程组的规模 n n n。
- 然后逐行读取矩阵数据,其中每一行包含 n n n个系数和1个常数项。
2.2 主元选择与行交换
for(ll i=1;i<=n;i++){for(ll k=i;k<=n;k++){if(im[k][i]!=0){if(k!=i){sp(im[k],im[i]);}break;}}// ...
}
- 对于第 i i i个未知数,选择列 i i i中第一个非零元素作为主元。
- 如果主元不在当前行,则交换行以将主元移至当前行。
函数sp的定义:
void sp(double*f,double*t){for(ll i=1;i<=n+1;i++){std::swap(f[i],t[i]);}
}
sp函数用于交换两行的数据。
2.3 主元归一化
double fact = im[i][i];
for(ll j=1;j<=n+1;j++){im[i][j]/=fact;
}
- 将主元所在的整行都除以主元,使得主元变为1,简化后续消元过程。
2.4 消元过程
for(ll k=1;k<=n;k++){if(k==i)continue;double fact = im[k][i];for(ll j=1;j<=n+1;j++){im[k][j]-=fact*im[i][j];}
}
- 对于除了当前主行之外的每一行,消去所在列的元素,使得每列只有主元为1,其他元素为0。
2.5 判断解的唯一性
if([]()->bool{for(ll i=1;i<=n;i++){bool isAllZero=true;for(ll j=1;j<=n;j++){if(im[i][j]!=0){isAllZero=false;}}if(isAllZero){return false;}}for(ll i=1;i<=n;i++){if(std::isnan(im[i][n+1])){return false;}}return true;
}()){std::cout<<std::fixed<<std::setprecision(2);for(ll i=1;i<=n;i++){std::cout<<im[i][n+1]<<'\n';}
}else{std::cout<<"No Solution\n";
}
- 通过一个lambda表达式判断方程组是否有唯一解。
- 检查所有主元行:
- 如果存在某一行系数全为0,但常数项不为0,说明方程组无解。
- 检查解的合理性:
- 如果某个解为
NaN(非数),说明方程组无唯一解。
- 如果某个解为
- 如果满足唯一解的条件,则输出结果,保留两位小数。
- 否则,输出
No Solution。
3. 代码中的关键点
3.1 数组下标从1开始
在这段代码中,数组的下标从1开始,而不是C++中常见的从0开始。这种设计可能是为了更贴近数学表达的习惯,使得代码更容易理解。
3.2 行交换与主元选择
选择主元并交换行是高斯消元法中的关键步骤,能够有效避免在消元过程中遇到除以0的情况,并提高算法的数值稳定性。
3.3 消元与归一化
通过对主元所在行进行归一化处理,使得主元为1,然后利用主元消去其他行同一列的元素,最终将矩阵转化为简化的上三角矩阵或单位矩阵。
3.4 解的判断
判断方程组是否有唯一解是高斯消元法中的重要部分。通过检查消元后的矩阵,可以确定方程组的解的性质。
4. 代码优化建议(不修改代码的前提下)
尽管用户要求不修改代码,但从学习的角度,可以提出一些优化建议:
- 使用零近似判断: 由于浮点数的精度问题,直接比较
im[k][i] != 0可能不可靠。可以引入一个极小的阈值,例如1e-9,判断abs(im[k][i]) > 1e-9。 - 更智能的主元选择: 当前代码选择的是首个非零元素作为主元,可以改为选择绝对值最大的元素以提高数值稳定性。
- 使用
vector替代固定大小的数组: 虽然本题数据范围较小,但在更复杂的场景下,vector提供了更大的灵活性。
四、实例解析
让我们通过给定的输入示例,手动模拟高斯消元法的过程,帮助理解代码的执行流程。
输入:
3
1 3 4 5
1 4 7 3
9 3 2 2
步骤:
-
初始增广矩阵:
1 3 4 | 5 1 4 7 | 3 9 3 2 | 2 -
第1步:选择第1列的主元
- 最大绝对值在第3行,元素为9。
- 交换第1行与第3行。
9 3 2 | 2 1 4 7 | 3 1 3 4 | 5 -
第2步:归一化主元行
- 主元为9,将整个第1行除以9。
1 0.3333 0.2222 | 0.2222 1 4 7 | 3 1 3 4 | 5 -
第3步:消元
-
消去第2行和第3行的第1列元素。
-
第2行减第1行:
0 3.6667 6.7778 | 2.7778 -
第3行减第1行:
0 2.6667 3.7778 | 4.7778
-
-
重复以上步骤,直到矩阵达到单位矩阵形式。
最终得到:
1 0 0 | -0.97
0 1 0 | 5.18
0 0 1 | -2.39
即:
x = -0.97
y = 5.18
z = -2.39
五、总结
本文通过一个具体的C++实现,详细解析了高斯消元法的基本原理和编程实现细节。高斯消元法作为求解线性方程组的经典算法,具有广泛的应用场景和重要的理论价值。在竞赛编程中,理解并掌握高斯消元法的实现,不仅能够帮助解决相关问题,还能提高对线性代数基础知识的理解。
在实际编程中,注意数值稳定性和特殊情况的处理至关重要。通过合理的主元选择和精确的浮点数运算,可以有效避免算法中的潜在问题。同时,合理的数据结构和优化技巧也能提升代码的性能和可读性。
希望通过本文,读者能够对高斯消元法有更深入的理解,并能在编程竞赛中灵活运用这一强大的工具。
相关文章:
高斯消元法及其C++实现
深入浅出高斯消元法及其C实现 本文章代码由博主编写但是文章由ChatGPT-o1-mini生成 博客食用更佳 在计算机算法竞赛中,线性方程组的求解是一个常见且基础的问题。高斯消元法作为一种经典的算法,因其高效和直观的特性,广泛应用于各种编程竞赛和…...
DeepSeek AI R1推理大模型API集成文档
DeepSeek AI R1推理大模型API集成文档 引言 随着自然语言处理技术的飞速发展,大语言模型在各行各业的应用日益广泛。DeepSeek R1作为一款高性能、开源的大语言模型,凭借其强大的文本生成能力、高效的推理性能和灵活的接口设计,吸引了大量开发…...
【算法-动态规划】、魔法卷轴: 两次清零机会整个数组最大累加和
【算法-动态规划】、魔法卷轴: 两次清零机会整个数组最大累加和 文章目录 一、dp1.1 题意理解1.2 整体思路1.3 具体思路1.4 代码 二、多语言解法 一、dp 1.1 题意理解 nums 数组, 有正负0, 使用最多两次魔法卷轴, 希望使数组整体的累加和尽可能大. 求尽可能大的累加和 其实就…...
【R】Dijkstra算法求最短路径
使用R语言实现Dijkstra算法求最短路径 求点2、3、4、5、6、7到点1的最短距离和路径 1.设置data,存放有向图信息 data中每个点所在的行序号为起始点序号,列为终点序号。 比如:值4的坐标为(1,2)即点1到点2距离为4;值8的坐标为(6,7)…...
深入浅出:探索 DeepSeek 的强大功能与应用
深入浅出:探索 DeepSeek 的强大功能与应用 在人工智能技术飞速发展的今天,自然语言处理(NLP)作为其重要分支,正逐渐渗透到我们生活的方方面面。DeepSeek 作为一款功能强大的 NLP 工具,凭借其易用性和高效性…...
西门子S7-200 PLC串口PPI转以太网通讯的模块链接方式
项目背景 某汽车零部件生产车间有30台自动化生产设备,控制系统采用西门子S7-200系列的CPU226。此前,设备的一个通讯端口用于和变频器进行自由口通讯,另一个通讯端口连接着一台昆仑通态触摸屏作为人机界面。车间计划进行智能化升级ÿ…...
win10向windows server服务器传输文件
win10向windows server服务器传输文件 遇到无法直接拖动文件进行传输时 解决方案: 1.点击显示选项 2.点击本地资源-详细信息 3.在窗口中选择你需要共享的磁盘 4.然后远程连接到Windows server服务器 5.登录Windows server服务器后,在此电脑下就能看…...
git服务器搭建,gitea服务搭建,使用systemclt管理服务
文章目录 页面展示使用二进制文件安装git服务下载选择架构使用wget下载安装 验证 GPG 签名服务器设置准备环境创建systemctl文件 备份与恢复备份命令 (dump)恢复命令 (restore) 页面展示 使用二进制文件安装git服务 所有打包的二进制程序均包含 SQLite,MySQL 和 Po…...
Mybatis快速入门与核心知识总结
Mybatis 1. 实体类(Entity Class)1.1 实体类的定义1.2 简化编写1.2.1 Data1.2.2 AllArgsConstructor1.2.3 NoArgsConstructor 2. 创建 Mapper 接口2.1 Param2.2 #{} 占位符2.3 SQL 预编译 3. 配置 MyBatis XML 映射文件(可选)3.1 …...
用docker在本地用open-webui部署网页版deepseek
前置条件 用Ollama在本地CMD窗口运行deepseek大模型-CSDN博客文章浏览阅读109次,点赞5次,收藏2次。首次运行需要下载deepseek的大模型包(大约5GB,根据本地网速的不同在半个小时到几个小时之间下载完成) ,并…...
2025.2.8——一、[护网杯 2018]easy_tornado tornado模板注入
题目来源:BUUCTF [护网杯 2018]easy_tornado 目录 一、打开靶机,整理信息 二、解题思路 step 1:分析已知信息 step 2:目标——找到cookie_secret step 3:构造payload 三、小结 一、打开靶机,整理信…...
前端实现在PDF上添加标注(1)
前段时间接到一个需求,用户希望网页上预览PDF,同时能在PDF上添加文字,划线,箭头和用矩形框选的标注,另外还需要对已有的标注进行修改,删除。 期初在互联网上一通搜索,对这个需求来讲发现了两个问…...
【CXX-Qt】1.1 Rust中的QObjects
本文涉及到了使用CXX-Qt将Rust、C和QML集成到Qt应用程序中的各个方面。下面,我将提供一个简单的示例,演示如何使用CXX-Qt来创建一个Rust结构体并将其作为QObject子类暴露给C和QML。 一、设置CXX-Qt环境 首先,确保您已经安装了Rust、CXX和CX…...
操作系统中的任务调度算法
一、引言 在操作系统中,任务调度算法是核心组件之一,它负责合理分配有限的 CPU 资源,以确保系统的高效运行和良好的用户体验。任务调度的目标是实现公平性、最小化等待时间、提高系统吞吐量,并最大化 CPU 的利用率。不同的任务调…...
GitCode 助力 Easy-Es,革新 Elasticsearch 开发体验
项目仓库(点击阅读原文链接可直达) https://gitcode.com/dromara/easy-es 项目背景:填补 Elasticsearch ORM 框架空白 在 Java 开发领域,Excel 和 Elasticsearch 的代码编写难度一直名列前茅,尤其是 Elasticsearch&a…...
线程同步(互斥锁与条件变量)
文章目录 1、为什么要用互斥锁2、互斥锁怎么用3、为什么要用条件变量4、互斥锁和条件变量如何配合使用5、互斥锁和条件变量的常见用法 参考资料:https://blog.csdn.net/m0_53539646/article/details/115509348 1、为什么要用互斥锁 为了使各线程能够有序地访问公共…...
EF Core中实现值对象
目录 值对象优点 值对象的需求 值类型的实现 值类型GEO的实现 值类型MultilingualString的实现 案例:构建表达式树,简化值对象的比较 值对象优点 把有紧密关系的属性打包为一个类型把领域知识放到类的定义中 class shangjia {long id;string nam…...
《从入门到精通:蓝桥杯编程大赛知识点全攻略》(十一)-回文日期、移动距离、日期问题
前言 在这篇博客中,我们将通过模拟的方法来解决三道经典的算法题:回文日期、移动距离和日期问题。这些题目不仅考察了我们的基础编程能力,还挑战了我们对日期处理和数学推理的理解。通过模拟算法,我们能够深入探索每个问题的核心…...
Kubernetes 最佳实践:Top 10 常见 DevOps/SRE 面试问题及答案
1. 如何在 Kubernetes 中设置资源请求和限制? 资源请求确保容器有最小资源量(CPU/内存),而限制则强制容器消耗的最大资源量。这有助于高效资源分配并防止资源争用。 示例: resources:requests:memory: "256Mi&…...
Docker Compose介绍及安装使用MongoDB数据库详解
在现代容器化应用部署中,Docker Compose是一种非常实用的工具,它允许我们通过一个docker-compose.yml文件来定义和运行多容器应用程序。然而,除了Docker之外,Podman也提供了类似的工具——Podman Compose,它允许我们在…...
科普:数据仓库中的“指标”和“维度”
在数据仓库中,指标和维度是两个核心概念,它们对于数据分析和业务决策至关重要。以下是对这两个概念的分析及举例说明: 一、指标 定义: 指标是用于衡量业务绩效的关键数据点,通常用于监控、分析和优化企业的运营状况。…...
11.swagger使用
菜单位置 未登录接口会返回401 登录的token存储的位置 配置文件swagger配置中将/dev-api修改/...
java高级知识之集合
前言 集合是java开发中的重点内容,需要掌握的东西很多,面试中可问的东西很多,无论是深度还是广度。集合框架中Collection对应的实现类如下所示,这些都是要完全掌握,一个可以分为三大类List集合、Set‘集合以及Map集合…...
deepseek + kimi 高效生成PPT
1.在deepseek中生成ppt大纲 2.将大纲复制到kimi中生成PPT kimi:https://kimi.moonshot.cn/...
hadoop之MapReduce:片和块
假如我现在500M这样的数据,如何存储? 500M 128M 128M 128M 116M 分为四个块进行存储。 计算的时候,是按照片儿计算的,而不是块儿。 块是物理概念,一个块就是128M ,妥妥的,毋庸置疑。 片是逻辑概念&…...
好好说话:深度学习扫盲
大创项目是和目标检测算法YOLO相关的,浅浅了解了一些有关深度学习的知识。在这里根据本人的理解做一些梳理。 深度学习是什么? 之前经常听到AI,机器学习,深度学习这三个概念,但是对于三者的区别一直很模糊。 AI&…...
ASP.NET Core的贫血模型与充血模型
目录 概念 需求 贫血模型 充血模型 总结 概念 贫血模型:一个类中只有属性或者成员变量,没有方法。充血模型:一个类中既有属性、成员变量,也有方法。 需求 定义一个类保存用户的用户名、密码、积分;用户必须具有…...
【愚公系列】《Python网络爬虫从入门到精通》001-初识网络爬虫
标题详情作者简介愚公搬代码头衔华为云特约编辑,华为云云享专家,华为开发者专家,华为产品云测专家,CSDN博客专家,CSDN商业化专家,阿里云专家博主,阿里云签约作者,腾讯云优秀博主&…...
Kubernetes控制平面组件:etcd(一)
云原生学习路线导航页(持续更新中) kubernetes学习系列快捷链接 Kubernetes架构原则和对象设计(一)Kubernetes架构原则和对象设计(二)Kubernetes架构原则和对象设计(三)kubectl 和 …...
2100年芜湖人的一天:张明的生活剪影
2100年芜湖人的一天:张明的生活剪影 破晓 6:30 "沙沙"的微风声轻轻掠过耳畔,杨柳的沙沙声混合着若有若无的鸟鸣,张明的意识从深邃的梦境中缓缓浮现。这并非真实的自然声响,而是他的脑机接口精心编织的唤醒交响曲。量子…...
