前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >高斯消元

高斯消元

作者头像
ACM算法日常
发布2019-11-25 23:08:38
5900
发布2019-11-25 23:08:38
举报

高斯消元

众所周知,高斯消元是线性代数中重要的一课。通过矩阵来解线性方程组。高斯消元最大的用途就是用来解多元一次方程组。

前置技能 1.线性方程组

线性方程组是各个方程关于未知量均为一次的方程组(例如 2 元 1 次方程组) 2.增广矩阵 就是在系数矩阵的右边添上一列,这一列是线性方程组的等号右边的值。(接下来会举例子说明)虽然我觉得没什么用

3.主元 一种变元。指在消去过程中起主导作用的元素

4.初等行列变换 用一非零的数乘以某一方程 把一个方程的倍数加到另一个方程 互换两个方程的位置

题目-Acwing883

题意描述

输入一个包含 n 个方程 n 个未知数的线性方程组。方程组中的系数为实数。求解这个方程组。下图为一个包含 m 个方程 n 个未知数的线性方程组示例:

输入格式

第一行包含整数。接下来行,每行包含个实数,表示一个方程的个系数以及等号右侧的常数。

输出格式

如果给定线性方程组存在唯一解,则输出共行,其中第行输出第个未知数的解,结果保留两位小数。如果给定线性方程组存在无数解,则输出“ ”。如果给定线性方程组无解,则输出“ ”。

数据范围

所有输入系数以及常数均保留两位小数,绝对值均不超过。

输入样例

3
1.00 2.00 -1.00 -6.00
2.00 1.00 -3.00 -9.00
-1.00 -1.00 2.00 7.00

输出样例:

1.00
-2.00
3.00

现在我们来解释一下样例 首先看到样例 小学生或者初中生都能解出其所对应的线性方程组 但是我们要考虑怎么使用代码来实现这个简单的过程

先考虑解的情况 线性方程组无非有三种情况(也可以根据矩阵的秩来判断) 有唯一解 无解 无穷多组解 无解的情况非常容易想到 就是等号左边不等于等号右边了 无穷多组解的情况就是现有的方程组个数不足以解出当前所有的未知数 剩下的情况不就是有唯一解的情况了吗!

将样例输入化成一个普通的增广矩阵(将系数和值整合到一起) 这样的矩阵我们很难直观的看出它的解

所以我们最终的目的就是要把矩阵化成如下形式 这样我们能非常直观的看出它的解简单来说高斯消元最后就是要搞出这玩意?

然后我们继续来看样例 怎样才能通过初等行列变换来得到我们想要的这个矩阵呢?对于样例 首先进行交换行 得到

消元按照一般人的习惯是从上往下消 很容易想到要一列一列消 这样才有可能得到完美矩阵(也就是我们需要的上三角形矩阵)

将第一行的第一个元素(也就是主元)变为

然后用第一行去消第二三行

然后我们发现第一列的元素在再次进行初等行列变换性质 3 的时候二三行已经没有影响了!接着消元我们得到

第三个方程只有一个变量了,我们可以直观的看到它的值 然后再倒着往上消元 我们就得到了我们想要的矩阵

最后总结出算法步骤 1.枚举每一列,找到绝对值最大的一行 2.将该行换为第一行 3.将该行第一个数变为 1 4.将下面所有行的当前列消成 0 5.迭代以上步骤

然后开始开心的写代码 代码如下

#include<bits/stdc++.h>
using namespace std;
const int N=110;
const double eps=1e-8;
int n;
double a[N][N];//增广矩阵
/*void out()
{//亲测 本人遇到最好用的高斯消元debug方式
    for (int i=0;i<n;i++)
    {
        for (int j=0;j<=n;j++)
            printf("%.2lf ",a[i][j]);
            puts("");
    }
    puts("");
}*/
int gauss()
{
    int row;//行
    int col;//列
    for (col=0,row=0;col<n;col++)//从每一列开始枚举
    {
        int t=row;
        for (int i=row;i<n;i++)//找到当前列绝对值最大的行
            if (fabs(a[i][col])>fabs(a[t][col]))
                t=i;
        if (fabs(a[t][col])<eps)  continue;//精度问题 判断当前列
        for (int i=col;i<n+1;i++) swap(a[t][i],a[row][i]);
        for (int i=n;i>=col;i--)  a[row][i]/=a[row][col];
        for (int i=row+1;i<n;i++)
            if (fabs(a[i][col])>eps)
                for (int j=n;j>=col;j--)
                    a[i][j]-=a[row][j]*a[i][col];//模拟消元
                    //out();
        row++;
    }
    if (row<n)//消元之后方程个数少于n
    {
        for (int i=row;i<n;i++)
            if (fabs(a[i][n])>eps)//出现零等于非零的情况
                return 2;//无解
        return 1;//无穷多组解
    }
    for (int i=n-1;i>=0;i--)
        for (int j=i+1;j<n;j++)
            a[i][n]-=a[j][n]*a[i][j];
    return 0;//唯一解
}
int main()
{
    scanf("%d",&n);
    for (int i=0;i<n;i++)
        for (int j=0;j<n+1;j++)
            scanf("%lf",&a[i][j]);
    int ans=gauss();
    if(ans==0)
    {
        for(int i=0;i<n;i++)
            printf("%.2lf\n",a[i][n]);
    }
    else if(ans==1)
        puts("Infinite group solutions");
    else if(ans==2)
        puts("No solution");
    return 0;
}

结束撒花~lalala

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-11-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 ACM算法日常 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 高斯消元
    • 前置技能 1.线性方程组
    • 题目-Acwing883
      • 题意描述
        • 输入格式
          • 输出格式
            • 数据范围
              • 输入样例
                • 输出样例:
                领券
                问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档