Skip to content

高斯消元 笔记

一、高斯消元

如果有以下方程组,可以用这样的方法求解:

{4x1+0x2+6x3=285x1+1x2+4x3=220x1+5x2+1x3=9

把它的系数提出来,得到以下矩阵:

{406|28514|22051|9}

基本思路是:通过更换各个方程的位置,并用加减消元法使得 i 式变为 j=inai,jxj=bj 的形式,这样子 n 式就是 an,nxn=bn,用代入法逐步回带即可。

看不懂上面的式子看下面的例子,可以看出从下往上一直代入即可解出所有解:

{x1+x2+x3+x4+x5=5x2+x3+x4+x5=4x3+x4+x5=3x4+x5=2x5=1

再说解这个方程:

  • 1 式往下找,找到第一个有系数的 x1,并交换到 1 式的位置。
{4x1+0x2+6x3=285x1+1x2+4x3=220x1+5x2+1x3=9{406|28514|22051|9}
  • 1 式乘上 a2,1a1,1 得到 1 式(下面未给出),即 54,在令 2 式等于 2 式减 1 式:
{4x1+0x2+6x3=280x1+1x272x3=130x1+5x2+1x3=9{514|280172|13051|9}
  • 对接下来每个 xii 式做相同操作:
{5x1+1x2+4x3=220x11x2+72x3=80x1+0x2+372x3=74{514|220172|800372|74}
  • 解出 x3=4,代入 2 式,解出 x2=1,将全部代入 1 式,解出 x1=1

高斯消元就是对这个矩阵进行如上操作,发现上面操作可以非常机械化的解方程,易于程序实现。

cpp
const double eps = 1e-7; // 绝对值小于 10^(-7) 的数我们就当它是 0 了
void gauss() {
    for (int i = 1; i <= n; i++) {
        int p = 0;
        for (int j = i; j <= n; j++)
            if (abs(a[j][i]) > eps) {
                p = j;
                break;
            }
        if (!p) {
            cout << "No Solution";
            return;
        }
        swap(a[i], a[p]);
        for (int j = i + 1; j <= n; j++) {
            double x = a[j][i] / a[i][i];
            for (int k = i; k <= n + 1; k++)
                a[j][k] -= a[i][k] * x;
        }
    }
    for (int i = n; i; i--) {
        a[i][i] = a[i][n + 1] / a[i][i];
        for (int j = i - 1; j; j--) {
            a[j][n + 1] -= a[j][i] * a[i][i];
            a[j][i] = 0;
        }
    }
    for (int i = 1; i <= n; i++)
        cout << fixed << setprecision(2) << a[i][i] << "\n";
}

无穷多个解:出现 ai,1ai,n=0bi=0 的情况。

无解:出现 ai,1ai,n=0bi0 的情况。

二、高斯-约旦消元

无需回带,直接把每一行都用加减消元消到只剩 ai,ixi=bi

找最大的系数来作为被减式是为了减少误差。

cpp
void gauss() {
    for (int i = 1; i <= n; i++) {
        int p = i;
        for (int j = 1; j <= n; j++) {
            if (abs(a[j][j]) > eps and j < i)
                continue;
            if (abs(a[j][i]) > abs(a[p][i]))
                p = j;
        }
        swap(a[i], a[p]);
        if (abs(a[i][i]) <= eps) continue;
        for (int j = 1; j <= n; j++) {
            if (i == j) continue;
            double x = a[j][i] / a[i][i];
            for (int k = i; k <= n + 1; k++)
                a[j][k] -= a[i][k] * x;
        }
    }
}

如果出现 ai,i=0bi0,无解。

如果出现 ai,i=0bi=0,无穷解。

最近更新