[模板] 高斯消元

6 篇文章 0 订阅
1 篇文章 0 订阅

求解方程

高斯消元法,是一种求解线性方程组的算法.
何为线性方程组?
就是这样一组方程:
{ a 1 1 x 1 + a 1 2 x 2 + ⋯ + a 1 n x n = A 1 a 2 1 x 1 + a 2 2 x 2 + ⋯ + a 2 n x n = A 2 … a n 1 x 1 + a n 2 x 2 + ⋯ + a n n x n = A n \begin{cases} a_{1_1}x_1+a_{1_2}x_2+\dots+a_{1_n}x_n=A_1\\ a_{2_1}x_1+a_{2_2}x_2+\dots+a_{2_n}x_n=A_2\\ \dots \\ a_{n_1}x_1+a_{n_2}x_2+\dots+a_{n_n}x_n=A_n\\ \end{cases} a11x1+a12x2++a1nxn=A1a21x1+a22x2++a2nxn=A2an1x1+an2x2++annxn=An
所有的未知量的指数都是 1 1 1.
这样的方程亦可以用这样的矩阵表示:
[ a 1 1 a 1 2 … a 1 n A 1 a 2 1 a 2 2 … a 2 n A 2 … … … … … … … …   … … a n 1 a n 2 … a n n A n ] \left[\begin{array}{cccc|c} a_{1_1} & a_{1_2} & \dots & a_{1_n} & A_1\\ a_{2_1} & a_{2_2} & \dots & a_{2_n} & A_2\\ \dots\dots & \dots\dots & \dots\dots & \dots\dots\ & \dots\dots\\ a_{n_1} & a_{n_2} & \dots & a_{n_n} & A_n\\ \end{array}\right] a11a21an1a12a22an2a1na2n annA1A2An
并称这样的矩阵为增广矩阵.
高斯消元法就是在增广矩阵上操作的.

思想

高斯消元法的思路和直接笔算的思路一致,具体(步骤)如下:

  1. 从方程集合中选择一个方程.
  2. 将这个方程的一个未知量( x k x_k xk)变为 1 1 1.
  3. 用这个方程将其他所剩方程的 x k x_k xk变换 0 0 0.
  4. 将这个方程从方程集合中删去.

变换规则(操作)如下:

  • (1)可以将矩阵一行所有元素同时乘一个非零数.(其实也可以乘 0 0 0,但谁会那样做呢 ? 我会)
  • (2)将矩阵一行的元素加到另一行上.
  • (3)将矩阵的两行交换.

这样可能比较难以理解,可以结合下例:
[ 1 2 − 1 − 6 2 1 − 3 − 9 − 1 − 1 2 7 ] \left[\begin{matrix} 1&2&-1&-6 \\ 2&1&-3&-9\\ -1&-1&2&7 \end{matrix}\right] 121211132697
对应方程组:
{ x 1 + 2 x 2 − x 3 = − 6 2 x 1 + x 2 − 3 x 3 = − 9 − x 1 − x 2 + 2 x 3 = 7 \begin{cases} x_1+2x_2-x_3=-6\\ 2x_1+x_2-3x_3=-9\\ -x_1-x_2+2x_3=7\\ \end{cases} x1+2x2x3=62x1+x23x3=9x1x2+2x3=7
这个方程的解是 x 1 = 1 , x 2 = − 2 , x 3 = 3 \begin{array}{ccc}x_1=1,x_2=-2,x_3=3 \end{array} x1=1,x2=2,x3=3.(什么?不规范?)
那么观察高斯消元的方法:
我们先通过操作(1)将这个矩阵变为:
[ 1 2 − 1 − 6 − 1 − 0.5 1.5 4.5 − 1 − 1 2 7 ] \left[\begin{matrix} 1&2&-1&-6 \\ -1&-0.5&1.5&4.5\\ -1&-1&2&7 \end{matrix}\right] 11120.5111.5264.57
然后通过操作(2)变为:
[ 1 2 − 1 − 6 0 1.5 0.5 − 1.5 0 1 1 1 ] \left[\begin{matrix} 1&2&-1&-6 \\ 0&1.5&0.5&-1.5\\ 0&1&1&1 \end{matrix}\right] 10021.5110.5161.51
现在第一行已经没有用了,将其从方程集合中删去:
注意,方程 1 在原增广矩阵中还是存在的.
[ 0 1.5 0.5 − 1.5 0 1 1 1 ] \left[\begin{matrix} 0&1.5&0.5&-1.5\\ 0&1&1&1 \end{matrix}\right] [001.510.511.51]
然后通过操作(1)变为:
[ 0 1.5 0.5 − 1.5 0 − 1.5 − 1.5 − 1.5 ] \left[\begin{matrix} 0&1.5&0.5&-1.5\\ 0&-1.5&-1.5&-1.5 \end{matrix}\right] [001.51.50.51.51.51.5]
然后通过操作(2)和步骤(4)变为:
[ 0 0 − 1 − 3 ] \left[\begin{matrix} 0&0&-1&-3 \end{matrix}\right] [0013]
在执行操作(1),变为:
[ 0 0 1 3 ] \left[\begin{matrix} 0&0&1&3 \end{matrix}\right] [0013]
然后观察原增广矩阵,变成了这样:
[ 1 2 − 1 − 6 0 1.5 0.5 − 1.5 0 0 1 3 ] \left[\begin{matrix} 1&2&-1&-6 \\ 0&1.5&0.5&-1.5\\ 0&0&1&3 \end{matrix}\right] 10021.5010.5161.53
在经过(1)次操作(1)得:
[ 1 2 − 1 − 6 0 1 1 3 − 1 0 0 1 3 ] \left[\begin{matrix} 1&2&-1&-6 \\ 0&1&\frac{1}{3}&-1\\ 0&0&1&3 \end{matrix}\right] 1002101311613
这个矩阵称为阶梯形矩阵,在通过一波操作之后变成了:
[ 1 0 0 1 0 1 0 − 2 0 0 1 3 ] \left[\begin{matrix} 1 & 0 & 0 & 1\\ 0 & 1 & 0 & -2\\ 0 & 0 & 1 &3 \end{matrix}\right] 100010001123
对应的就是上面的解.
这个矩阵就是简化阶梯形矩阵.
高斯消元法的本质就是将一般的增广矩阵变换为简化阶梯形矩阵.
别想用 i n t int int d o u b l e double double就好.

特殊情况

当然,这只是“一路顺风”的情况.还有可能“一路逆风”
比如,平常我们解的方程组有可能无解,也有可能有无数组解.
那么在增广矩阵中怎么判断?
首先,如果发现了这样的情况:
[ 0 0 0 … 0 k ] \left[\begin{array}{ccccc|c} 0&0&0&\dots&0&k \end{array}\right] [0000k]
就肯定不是正常情况了.
很容易想到如下的讨论形式:
{ I n f i n i t e   n u m b e r   o f   s o l u t i o n s k = 0 N o   s o l u t i o n o t h e r s ( k ≠ 0 ) \begin{cases} Infinite\ number\ of\ solutions&k=0\\ No\ solution&others(k\neq0) \end{cases} {Infinite number of solutionsNo solutionk=0others(k̸=0)
当然,如果坚持做完高斯消元的话,这个矩阵可能会变成这个样子(要用到所有步骤和操作):
[ 1 0 0 k 1 0 0 0 0 0 0 0 k 3 ( k ≠ 0 ) ] \left[\begin{array}{ccc|c} 1&0&0&k_1\\ 0&0&0&0\\ 0&0&0&k_3(k\neq0)\\ \end{array}\right] 100000000k10k3(k̸=0)
很显然,这个方程是无解的(别的解再多这个坎就是过不去).
所以我们又将这个搞定了.
顺便说一下,对于 0 = 0 0=0 0=0这样的 I N F   S o l u t i o n s INF\ Solutions INF Solutions的情况,那些随便取值而不会影响结果的(有无限种取值的)为自由元,只能根据自由元取值的(受自由元约束的)为主元.
举个例子:
{ x 1 = 4 − x 2 x 3 = 1 \begin{cases} x_1=4-x_2\\ x_3=1 \end{cases} {x1=4x2x3=1
其中 x 2 x_2 x2为自由元, x 1 , x 3 x_1,x_3 x1,x3为主元.
或者变换一下方程(1), x 1 x_1 x1就会变为自由元, x 2 , x 3 x_2,x_3 x2,x3就是主元.

一系列的判断

众所周知我很懒,希望能简化步骤.
这里不想看可以跳过.
所以,给出以下几个判断:

  1. 我们可以每次用这个方程的非零系数中最高的那一项进行操作
    主要是因为我们懒,每次反正都要删去系数非零的最高项,顺序可以不一.
  2. 当我们发现有一项所有方程都没有时,就可以准备进入 I N F   S o l u t i o n s INF\ Solutions INF Solutions N o   S o l u t i o n No\ Solution No Solution的判断了.
    很简单,这项取什么都不会影响结果.
    但是万一发生了上面矩阵的情况?所以只能准备,不能直接判断.
  3. 当一行所有系数都为 0 0 0时,直接返回 I N F   S o l u t i o n s INF\ Solutions INF Solutions N o   S o l u t i o n No\ Solution No Solution.
    这无需进行讨论…吧.

时间复杂度

选择各项 O ( n ) O(n) O(n).
选择合适的方程(行) O ( n ) O(n) O(n).
处理其他行 O ( n ) O(n) O(n).
总的时间复杂度 O ( n 3 ) O(n^3) O(n3).
还是很暴力优秀的.

Code

题目传送门
话说这题有点怪…

#include<bits/stdc++.h>
using namespace std;
const int N=105;
int n;
double a[N][N];
bool iszero(double x)
{
    return abs(x)<1e-6;
}
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 p;
        for (p=i;p<=n;p++)
            if (!iszero(a[i][p])) break;
        if (p>n)
        {
            if (!iszero(a[i][n+1])) printf("No Solution");
            else printf("No Solution");//printf("INF Solutions");
            return 0;
        }
        for (int j=n+1;j>=p;j--)
            a[i][j]/=a[i][p];
        for (int j=i+1;j<=n;j++)
            for (int k=n+1;k>=p;k--)
                a[j][k]-=a[j][p]*a[i][k];
    }
    for (int i=n;i>=1;i--)
        for (int j=i-1;j>=1;j--)
        {
            a[j][n+1]-=a[j][i]/a[i][i]*a[i][n+1];
            a[j][i]=0;
        }
    for (int i=1;i<=n;i++) printf("%.2lf\n",a[i][n+1]);
    return 0;
}

感谢奆老关注 qwq ?

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值