算法设计与分析:高斯消去法

前向消去

// 输入任意矩阵的引用,返回的布尔变量表示矩阵是否有唯一解
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;
} 

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值