前向消去
// 输入任意矩阵的引用,返回的布尔变量表示矩阵是否有唯一解
bool ForwardElimination(vector<vector<double>>& matrix) {
// 开始前向消元过程,遍历矩阵的行,注意不需要遍历最后一行
for(int i = 0; i < matrix.size() - 1; i++) {
// 部分选主元法,从当前行到最后一行中,找到第 i 列中绝对值最大的元素所在的行
int pivotrow = i;
for(int j = i + 1; j < matrix.size(); j++) {
if(abs(matrix[j][i]) > abs(matrix[pivotrow][i])) {
pivotrow = j;
}
}
// 如果找到的最大值为零,则表示解不唯一或无解
if(matrix[pivotrow][i] == 0) {
return false;
}
// 将找到的最大值所在的行与第 i 行进行交换
for(int k = i; k < matrix.size() + 1 && i != pivotrow; k++) {
swap(matrix[i][k], matrix[pivotrow][k]);
}
// 将第 i+1 行到最后一行的方程组都减去第 i 行乘以一个数得到的方程组
for(int j = i + 1; j < matrix.size(); j++) {
double temp = matrix[j][i] / matrix[i][i];
for(int k = i; k < matrix.size() + 1; k++) {
matrix[j][k] = matrix[j][k] - matrix[i][k] * temp;
}
}
}
// 需要单独检测上三角形的对角线上最后一个元素是否为零,如果为零,则表示解不唯一或无解
if(matrix[matrix.size() - 1][matrix.size() - 1] == 0) {
return false;
}
// 若通过以上检测,则返回 true,表示矩阵有唯一解
return true;
}
为什么不需要遍历最后一行 :前向消元的目的是将矩阵转换为上三角形式。在转换过程中,主要操作是在第 i 行之下的各行中消去当前列(即第 i 列) 。这个操作仅涉及到当前行和其下方的行。因此,当遍历到倒数第二行时,已经完成了上三角化 。最后一行无需进一步处理,因为它已经处于上三角形的底部,没有下方的行需要消除。“将第 i+1 行到最后一行的方程组都减去第 i 行乘以一个数得到的方程组”的目的是什么 :①temp = matrix[j][i] / matrix[i][i]
计算行 j
和 i
之间需要的缩放因子 。②然后通过循环 for (int k = i; k < matrix.size() + 1; k++)
对行 j
进行更新,将行 i
的缩放版本减去行 j
的当前值,从而将列 i
在行 j
中的元素变为零 。这是消去下方行中第 i 列元素的关键步骤。为什么需要单独检测上三角形的对角线上最后一个元素是否为零? :如果对角线元素为零,这一行中的线性方程无法提供关于变量的任何信息,意味着系统可能具有无穷多解或无解
反向替换的实现
// 函数返回解向量
vector<double> BackSubstitution(vector<vector<double>>& matrix){
vector<double> solution(matrix.size(), 0); //创建了一个与矩阵行数相同的 double 类型向量 solution,并初始化为全零,用于存储解向量
for(int i=matrix.size()-1; i>=0; i--){ //从矩阵的最后一行开始,逐行向上遍历
for(int j=matrix.size()-1; j>i;j--){ //在每一行 i 上,从该行的最后一个元素向前遍历,直到 i,这确保了只处理上三角矩阵中非零元素的位置
matrix[i][matrix.size()] -= matrix[i][j]*solution[j]; //更新矩阵最后一列(右侧向量)中的值
}
solution[i] = matrix[i][matrix.size()] / matrix[i][i]; //计算当前行 i 的解
}
return solution;
}
matrix[i][matrix.size()] -= matrix[i][j]*solution[j];
:这行代码是在进行回代,更新矩阵最后一列(右侧向量)中的值。它通过减去上一行已知变量的影响来计算该行的解。具体来说,matrix[i][matrix.size()]
存储了等式右侧的常数项,然后减去已知变量的乘积(即 matrix[i][j]*solution[j]
)( 3X2 - 3X3 = 3并且X3 = 3,则X2 = (3-(-3)*X3)/3 ) solution[i] = matrix[i][matrix.size()] / matrix[i][i];
:计算当前行 i
的解,并将其存储在解向量 solution
中。这里的计算是通过将右侧常数项除以对角线上的系数来完成的 。
高斯消元求解方程组
#include<iostream>
#include<vector>
#include<iomanip>
#include<cmath>
using namespace std;
void swap(double& a, double& b){
double temp = a;
a = b;
b = temp;
}
bool ForwardElimination(vector<vector<double>>& matrix){
for(int i=0; i<matrix.size()-1; i++){
int pivotrow = i;
for(int j=i+1; j<matrix.size(); j++){
if(abs(matrix[j][i]) > abs(matrix[pivotrow][i])){
pivotrow = j;
}
}
if(matrix[pivotrow][i] == 0){
return false;
}
for(int k=i; k<matrix.size()+1 && i != pivotrow; k++){
swap(matrix[i][k], matrix[pivotrow][k]);
}
for(int j=i+1; j<matrix.size(); j++){
double temp = matrix[j][i] / matrix[i][i];
for(int k=i; k<matrix.size()+1; k++){
matrix[j][k] = matrix[j][k] - matrix[i][k]*temp;
}
}
}
if(matrix[matrix.size()-1][matrix.size()-1] == 0){
return false;
}
return true;
}
vector<double> BackSubstitution(vector<vector<double>>& matrix){
vector<double> solution(matrix.size(), 0);
for(int i=matrix.size()-1; i>=0; i--){
for(int j=matrix.size()-1; j>i;j--){
matrix[i][matrix.size()] -= matrix[i][j]*solution[j];
}
solution[i] = matrix[i][matrix.size()] / matrix[i][i];
}
return solution;
}
int main()
{
int n;
cin >> n;
vector<vector<double>> matrix(n, vector<double>(n+1, 0));
for(int i=0; i<n; i++){
for(int j=0; j<n+1; j++){
cin >> matrix[i][j];
}
}
bool onlyS = ForwardElimination(matrix);
if(onlyS){
vector<double> solution = BackSubstitution(matrix);
for(int i=0; i<solution.size(); i++){
cout << fixed <<setprecision(2) << solution[i] << endl;
}
}else{
cout << "No Solution";
}
return 0;
}