• 高斯消元(写(shui)题必备)


    前言:
    在一次学校hu测中,
    遇到一道正解不用高斯消元,但是部分分需要的中档题
    用舒老师的话说,只要是会高斯消元和树形dp
    乱搞一下那道题就可以水到70
    所以还是学习一下这个很有用算法:高斯消元

    简介


    数学上,高斯消元法(或译:高斯消去法),是线性代数中的一个算法,
    可用来为线性方程组求解,求出矩阵的秩,以及求出可逆方阵的逆矩阵。
    当用于一个矩阵时,高斯消元法会产生出一个“行梯阵式”
    高斯消元法可以用在电脑中来解决数千条等式及未知数。
    不过,如果有过百万条等式时,这个算法会十分费时。一些极大的方程组通常会用迭代法来解决。
    亦有一些方法特地用来解决一些有特别排列的系数的方程组。

    手玩

    高斯消元简单来说就是我们平时的解方程
    然而我在简介中提到了一个“行梯阵式”

    行梯矩阵
    指一个矩阵每个非零行的非零首元都出现在上一行非零首元的右边,
    同时没有一个非零行出现在零行之下。
    如:
    1 3 0 1
    0 2 1 0
    0 0 0 1

    我们还是稍微来看一下手玩版的高斯消元

    下面的是咱们要求解的线性方程组,先把四个方程编上序号。
    这里写图片描述

    先把第一行乘以1/2,然后把第一行的相应倍数加到第二、三、四行上。
    这里写图片描述

    再把第二行乘以-2,接着将其相应的倍数加到第三、四行上,然后把第三行乘以-1/6。
    这里写图片描述

    将第三行的二倍加到第四行上,再把第四行乘以3/7。
    这里写图片描述

    然后往回代,就是把第四行的相应倍数加到第一、第二、第三行上;
    把第三行的相应倍数加到第一、第二行上。
    这里写图片描述

    再把第二行的相应倍数加到第一行上,最后根据得出的矩阵列出方程组,解得最后的解。
    这里写图片描述

    总结上面过程,高斯消元法其实就是下面非常简单的过程

    原线性方程组 ——> 高斯消元法 ——> 下三角或上三角形式的线性方程组 ——> 前向替换算法求解(对于上三角形式,采用后向替换算法)

    转换为行阶梯阵,判断解的情况。

    ① 无解
    当方程中出现(0, 0, …, 0, a)的形式,且a != 0时,说明是无解的。
    这里写图片描述

    ② 唯一解
    条件是k = equ,即行阶梯阵形成了严格的上三角阵。利用回代逐一求出解集。
    这里写图片描述

    ③ 无穷解。
    条件是k < equ,即不能形成严格的上三角形,自由变元的个数即为equ – k,但有些题目要求判断哪些变元是不确定的。
    这里写图片描述

    这里单独介绍下这种解法:
    首先,自由变元有var - k个,即不确定的变元至少有var - k个。
    我们先把所有的变元视为不确定的。
    在每个方程中判断不确定变元的个数,如果大于1个,则该方程无法求解。
    如果只有1个变元,那么该变元即可求出,即为确定变元。

    程序实现

    bool guass()
    {
        int now=1,to;
        double t;
        for (int i=1;i<=n;i++)   //枚举未知量 
        {
            for (to=now;to<=n;to++)
                if (fabs(a[to][i])>eps) break;
            if (to>n) continue;
            if (to!=now)
               for (int j=1;j<=n+1;j++)
                   swap(a[to][j],a[now][j]);
            t=a[now][i];
            for (int j=1;j<=n+1;j++) a[now][j]/=t;  //系数化为一 
            for (int j=1;j<=n;j++)
                if (j!=now)
                {
                    t=a[j][i];
                    for (int k=1;k<=n+1;k++)
                        a[j][k]-=t*a[now][k];
                }
            now++;
        }
        for (int i=now;i<=n;i++)
            if (fabs(a[i][n+1])>eps) return 0;
        return 1;
    }

    我尝试这解释一下这个函数是怎么发挥作用的:
    我们要调用这个函数的前提是我们已经有了一个阵式

    for (int i=1;i<=n;i++)   //枚举未知量 

    实际上就是模拟手玩过程中一行一行进行消元
    (第i行消掉的一定是第i个未知量)

    变量now和to:
    因为我们最后计算出来的一定是行阶阵式
    now记录的就是当前行从左起第一个非零元素的位置

    for (to=now;to<=n;to++)
        if (fabs(a[to][i])>eps) break;

    找到未处理的方程中,第now个未知量的系数不为零的方程
    (这些方程是需要消元的)

    t=a[now][i];
    for (int j=1;j<=n+1;j++) a[now][j]/=t;  //系数化为一 

    方程的所有系数都除以t
    以此为基准进行之后的消元

    for (int j=1;j<=n;j++)
        if (j!=now)
        {
            t=a[j][i];
            for (int k=1;k<=n+1;k++)
            a[j][k]-=t*a[now][k];
        }
    now++;

    其余的每一行进行消元
    完成之后now++
    相当于整个方程组减少了一个未知量

    for (int i=now;i<=n;i++)
        if (fabs(a[i][n+1])>eps) return 0;

    最后有一个很简单的判断
    看一下是不是唯一解

  • 相关阅读:
    7种jvm垃圾回收器,这次全部搞懂
    3分钟学会redis主从复制搭建,及原理
    一文搞懂什么是递归,程序员必会算法之一
    Redis持久化方式:RDB和AOF详解,对比
    jvm垃圾回收算法详解,看这一篇就够了(求点赞)
    Redis命令大全,满足你的日常工作,看这一篇就够了(求点赞)
    Java自定义异常为什么性能差(求点赞)阿里双十一的性能凶手之一
    jvm类加载器,类加载机制详解,看这一篇就够了(求点赞)
    show processlist 命令详解,MySQL优化看这一篇就够了
    asp.net中的post和get请求操作
  • 原文地址:https://www.cnblogs.com/wutongtong3117/p/7673087.html
Copyright © 2020-2023  润新知