高斯消元

高斯消元

本文转自 Acwing题解板块

  • 通过初等行变换把增广矩阵化为阶梯型矩阵,并回代得到方程的解
  • 适用于求解 包含\(n\) 个方程,\(n\) 个未知数的多元线性方程组
    例如方程组:

\[\left\{ \begin{array}{} &a_{11}x_1+&a_{12}x_2+\cdots+&a_{1n}x_n=&b_1 \\ &a_{21}x_1+&a_{22}x_2+\cdots+&a_{2n}x_n=&b_2 \\ &\vdots&\vdots&\vdots&\vdots \\ &a_{n1}x_1+&a_{n2}x_2+\cdots+&a_{nn}x_n=&b_n \\ \end{array} \right. \]

增广矩阵为:

\[\begin{pmatrix}{} a_{11}&a_{12}&\cdots&a_{1n}&b_1 \\ a_{21}&a_{22}&\cdots&a_{2n}&b_2 \\ \vdots&\vdots&\vdots&\vdots&\vdots \\ a_{n1}&a_{n2}&\cdots&a_{nn}&b_n\\ \end{pmatrix} \]

  • 接下来所有的操作都使用增广矩阵代替原方程组

前置知识:初等行(列)变换

1.把某一行乘一个非\(0\)的数 (方程的两边同时乘上一个非\(0\)数不改变方程的解)
2.交换某两行(交换两个方程位置)
3.把某一行的若干倍加到某一行上去(把某一个方程的若干倍加到另一个方程上去)

接下来,利用初等行变化,把增广矩阵化为阶梯型矩阵

阶梯型矩阵:

\[\begin{pmatrix}{} a_{11}&a_{12}&\cdots&a_{1n}&b_1 \\ &a_{22}&\cdots&a_{2n}&b_2 \\ &&&\vdots&\vdots \\ &&&a_{nn}&b_n\\ \end{pmatrix} \]

最后再把阶梯型矩阵从下到上回代到第一层即可得到方程的解

算法步骤

枚举每一列c

  • 找到当前这一列绝对值最大的数所在的行.
  • 用行变换(2)把这一行换到最上面(未确定阶梯型的行,并不是第一行).
  • 用初等行变换(1) 将该行的第一个数变成 \(1\) (其余所有的数字依次跟着变化).
  • 用初等行变换(3) 将下面所有行的当且列的值变成 \(0\).

模板题:Acwing.883

#include <algorithm>
#include <iostream>
#include <cstring>
#include <string>
#include <cstdio>
#include <vector>
#include <queue>
#include <cmath>
#include <map>
#include <set>

#define fi first
#define se second
#define rep(i,n) for(int i=0;i<(n);++i)
#define repA(i,a,n) for(int i=a;i<=(n);++i)
#define repD(i,a,n) for(int i=a;i>=(n);--i)
using namespace std;
using LL = long long;

const int N = 110;
const double eps = 1e-6;
double a[N][N];
int n;

int gauss()
{
    int c, r;
    for (c = 0, r = 0; c < n; ++ c) 
    {
        // 找到当前这一列最大的数所在的行,把它与r行进行交换
        int t = r;
        for (int i = r; i < n; ++ i)
        {
            if (fabs(a[i][c]) > fabs(a[t][c]))
                t = i;
        }
        //都为0,就没必要交换
        if (fabs(a[t][c]) < eps) continue; 
        for (int i = c; i <= n; ++ i) swap(a[t][i], a[r][i]);
        //把当前行对应的阶梯数变为1
        for (int i = n; i >= c; --i) a[r][i] /= a[r][c];

        //把阶梯数这一列下面的数字都变为0
        for (int i = r + 1; i < n; ++ i)
            if (fabs(a[i][c]) > eps)
                for (int j = n; j >= c; -- j)
                    a[i][j] -= a[r][j] * a[i][c];

        r ++;//当前行已变为阶梯行,接着处理下一行
    }
    if (r < n)
    {
        // 因为已经是阶梯型,所以 r ~ n-1 的值应该都为 0
        for (int i = r; i < n; ++ i)
            if (fabs(a[i][n]) > eps) return 2;
        return 1;// 否则, 0 = 0,就是r ~ n-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()
{
    // ios::sync_with_stdio(0);
    // cin.tie(0);
    // cout.tie(0);
    cin >> n;
    rep(i, n)
        repA(j, 0, n)
            cin >> a[i][j];
    
    int t = gauss();

    if (t == 0)
    {
        rep(i, n) printf("%.2f\n", a[i][n]);
    }
    else if (t == 1) puts("Infinite group solutions");
    else puts("No solution");
    return 0;
}

高斯消元解异或线性方程组:Acwing.884
同上一题一样,异或是不进位的加法,把上面的模板的加法用异或替代即可。

#include <algorithm>
#include <iostream>
#include <cstring>
#include <string>
#include <cstdio>
#include <vector>
#include <queue>
#include <cmath>
#include <map>
#include <set>

#define fi first
#define se second
#define rep(i,n) for(int i=0;i<(n);++i)
#define repA(i,a,n) for(int i=a;i<=(n);++i)
#define repD(i,a,n) for(int i=a;i>=(n);--i)
using namespace std;
using LL = long long;

const int N = 110;
int a[N][N];
int n;

int gauss()
{
    int c, r;
    for (c = 0, r = 0; c < n; ++ c) 
    {
        // 找到当前这一列最大的数所在的行,把它与r行进行交换
        int t = r;
        for (int i = r; i < n; ++ i)
        {
            if (a[i][c])
            {
                t = i;
                break;
            }
        }
        //都为0,就没必要交换
        if (a[t][c] == 0) continue; 
        for (int i = c; i <= n; ++ i) swap(a[t][i], a[r][i]);

        //把阶梯树这一列下面的数字都变为0
        for (int i = r + 1; i < n; ++ i)
            if (a[i][c])
                for (int j = n; j >= c; -- j)
                    a[i][j] ^= a[r][j];

        r ++;//当前行已变为阶梯行,接着处理下一行
    }
    if (r < n)
    {
        // 因为已经是阶梯型,所以 r ~ n-1 的值应该都为 0
        for (int i = r; i < n; ++ i)
            if (a[i][n]) return 2;
        return 1;// 否则, 0 = 0,就是r ~ n-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()
{
    // ios::sync_with_stdio(0);
    // cin.tie(0);
    // cout.tie(0);
    cin >> n;
    rep(i, n)
        repA(j, 0, n)
            cin >> a[i][j];
    
    int t = gauss();

    if (t == 0)
    {
        rep(i, n) printf("%d\n", a[i][n]);
    }
    else if (t == 1) puts("Multiple sets of solutions");
    else puts("No solution");
    return 0;
}
posted @ 2020-04-08 22:17  niyada  阅读(179)  评论(0)    收藏  举报