高斯消元

1.高斯消元的基础信息

本质

通过初等行变化,将线性方程组的增广矩阵转化为行阶梯矩阵,讲人话就是用加减消元来转化,代入消元来回带。

应用

用来求解线性方程组(m个一次方程,n个变量),矩阵的秩(校园后的主元数)以及求可逆方阵的逆矩阵。

难度

思维难度低,代码实现难度低

复杂度

时间:O(n^3)空间:O(nm)

2.高斯消元的算法流程(以下图为例)

1.构造增广矩阵(系数与常数项):

1  -2   1   0
0   2  -8   8
-4  5   9  -9

2.通过以交换行、某行乘以非负常数和两行相加这三种初等变化将原系统转化为更简单的三角形式

1  -2   1   0     1 -2  1  0     1 -2  1  0     
0   2  -8   8     0  1 -4  4     0  1 -4  4
0  -3  13  -9     0 -3 13 -9     0  0  1  3

3.回带求解(用方程理解)

x1-2*x2+x3=0
x2-4*x3=4
x3=3

从最后一行开始推,x3=3,x2=16,x1=29就是结果

3.代码详解

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
double map[111][111];
double ans[111];
double eps=1e-7;
int main(){
    int n;
    cin>>n;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n+1;j++)
            scanf("%lf",&map[i][j]);
    for(int i=1;i<=n;i++){
        int r=i;
        for(int j=i+1;j<=n;j++)
            if(fabs(map[r][i])<fabs(map[j][i]))
                r=j;//找本列最大的主元
        if(fabs(map[r][i])<eps)//最大的主元为0,则无解或无数解
     { printf(
"No Solution"); return 0; } if(i!=r)swap(map[i],map[r]);//对换一行或一列,属于找最大当前系数的其中一步。(这样就可以只处理当前行的系数啦!) double div=map[i][i]; for(int j=i;j<=n+1;j++) map[i][j]/=div;//系数化为1 for(int j=i+1;j<=n;j++){//i行后面的行的第i个清为0 div=map[j][i]; for(int k=i;k<=n+1;k++) map[j][k]-=map[i][k]*div; } } ans[n]=map[n][n+1]; for(int i=n-1;i>=1;i--){ ans[i]=map[i][n+1]; for(int j=i+1;j<=n;j++) ans[i]-=(map[i][j]*ans[j]); }//回带操作 for(int i=1;i<=n;i++) printf("%.2lf\n",ans[i]); }

4.高斯约旦算法

大体相似,将增广矩阵消为只有对角线有值的矩阵

#include <bits/stdc++.h>
using namespace std;
const double eps=1E-20;
int n;
double a[110][110];
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n+1;j++)
        {
            scanf("%lf",&a[i][j]);
        }
    }
    for(int i=1;i<=n;i++)
    {
        int max=i;
        for(int j=i+1;j<=n;j++)
        {
            if(fabs(a[j][i])>fabs(a[max][i]))max=j;
        }
        for(int j=1;j<=n+1;j++)swap(a[i][j],a[max][j]);
        if(fabs(a[i][i])<=eps)
        {
            printf("No Solution\n");
            return 0;
        }
        for(int j=1;j<=n;j++)//最主要的不同,从一开始循环
        {
            if(i==j)continue;
            double tmp=a[j][i]/a[i][i] ;
            for(int k=i+1;k<=n+1;k++)
            {
                a[j][k]-=a[i][k]*tmp;
            }
        }
    }
    for(int i=1;i<=n;i++)
    {
        printf("%.2lf\n",a[i][n+1]/a[i][i]);
    }
    return 0;
 } 

5.对比

高斯约旦无需回带,代码更简单,但只能判断是否有唯一解,无法判断究竟是无解还是无数解。

高斯可以需回带,可以判断无解,无数解,唯一解

6.判解

对于无解的判断:某一行前n个数均为 0,最后的结果却不为0。

对于无数解的判断:某一行n+1个数均为0.

无解无数解的共同特点某一行前n个数都为0(有一个主元为0则)。

否则有唯一解。

posted @ 2024-08-11 19:38  storms11  阅读(6)  评论(0编辑  收藏  举报