总结:高斯消元

总结:高斯消元

\(O(n^2m)\) 求解 \(n\)线性方程组 + 判断解的情况(可以是模意义下)
\(O(\frac{n^2m}{w})\) 求解 \(n\)异或方程组 + 判断解的情况


求解有唯一解的 \(n\)线性方程组

高斯消元基础

#1:高斯消元法

这里总结一下,对于一个有唯一解的增广矩阵,高斯消元分 5 步:

  1. 找主元
  2. 当前行的方程主元系数化为一
  3. 当前行以下的方程消去主元
  4. 如果还有别的主元,回到 1
  5. 对于消完的上三角矩阵一行行回带

版子:

inline void gauss()
{
    int i, j, k;
    double div;

    for (k = 1; k <= n; k ++)
    {
        //1. 找主元
        int mi = k;
        for (i = k + 1; i <= n; i ++)
            if (fabs(g[i][k]) > fabs(g[mi][k]))
                mi = i;
        swap(g[mi], g[k]);

        //2. 将**当前行**的方程主元系数化为一
        div = g[k][k];
        for (j = k; j <= n + 1; j ++)
            g[k][j] /= div;

        //3. 将**当前行以下**的方程消去主元
        for (i = k + 1; i <= n; i ++)
        {
            div = g[i][k];
            for (j = k; j <= n + 1; j ++)
                g[i][j] -= g[k][j] * div;
        }

        //4. 如果还有别的主元,回到 1
    }

    //5. 对于消完的上三角矩阵一行行回带
    for (k = n; k >= 1; k --)
    {
        a[k] = g[k][n + 1];
        for (j = k + 1; j <= n; j ++)
            a[k] -= g[k][j] * a[j];
    }
}   

#2:高斯-约旦消元法

注意到高斯消元法只将当前行以下的方程消去主元,这使得最后消完为一个上三角矩阵,导致还要一行行回带

如果这里我们直接将除了当前行以外的所有行都消去主元,最后的结果为一溜斜着的 1,可以省去回带

总结一下即分 4 步:

  1. 找主元
  2. 当前行的方程主元系数化为一
  3. 除当前行以外的方程消去主元
  4. 如果还有别的主元,回到 1

版子:

inline void gauss_jordan()
{
    int i, j, k;
    double div;

    for (k = 1; k <= n; k ++)
    {
        //1. 找主元
        int mi = k;
        for (i = k + 1; i <= n; i ++)
            if (fabs(g[i][k]) > fabs(g[mi][k]))
                mi = i;
        swap(g[k], g[mi]);

        //2. 将**当前行**的方程主元系数化为一
        div = g[k][k];
        for (j = 1; j <= n + 1; j ++)
            g[k][j] /= div;

        //3. 将**除当前行以外**的方程消去主元
        for (i = 1; i <= n; i ++)
        {
            if (i == k)
                continue;
            div = g[i][k];
            for (int j = 1; j <= n + 1; j ++)
                g[i][j] -= g[k][j] * div;
        }

        //4. 如果还有别的主元,回到 1
    }

    //无需回带
    for (i = 1; i <= n; i ++)
        a[i] = g[i][n + 1];
}

求解不保证有唯一解的 \(n\) 元线性方程组

这里探讨一下什么情况会出现无解和有无数解:

  • 无解:解着解着发现形如 \(0=4\) 的神秘东西
  • 无数解:方程给的太少或消成了 \(0=0\) 的东西

做法:

高斯消元法与高斯-约旦消元法是一样的

如果出现上述任意情况会在某一列找不到主元,就去下一列找。

同时维护一个变量 \(c\) 为待消去的主元编号,即整个过程进行完后 \(c\sim n\) 的方程未知数系数全为 0;

if (g[mi][k] == 0)
    continue;
swap(g[c], g[mi]);

/*
和模版一样
*/

c ++;

最后根据是 \(0=0\) 的情况还是 \(0=?\) 的情况判断有无解

if (c <= n)
{
    for (; c <= n; c ++)
        if (g[c][n + 1] != 0)
        {
            printf("No Solution\n");
            exit(0);
        }
    printf("Infinity Solution\n");
    exit(0);
}

求解方程数量不保证等于未知数数量的 \(n\) 元线性方程组。

设方程数量为 \(m\),则无论是高斯消元法还是高斯-约旦消元法的做法都一样

记得改变一些枚举变量的上界,并在判断解的情况时注意分讨即可

if (c <= max(n, m))
{
    for (; c <= m; c ++)
        if (g[c][n + 1] != 0)
        {
            printf("No Solution\n");
            exit(0);
        }
    if (c <= n)
    {
        printf("Infinity Solution\n");
        exit(0);
    }
}

求解模 \(p\) 意义下的 \(n\) 元线性方程组

\(p\) 为质数

这种情况下可以直接除法改逆元,做就好了

\(p\) 为合数

做除法时暴力对被除数加 \(p\) 指导能整除为止,这个过程的复杂度没有保证,一般这种题出题人会有说明


求解异或方程组

这种方程可由模 \(2\) 的同余方程组转化而来

因为异或的优秀性质,我们消元时直接异或就好,这样整个过程就可以使用 bitset 优化,时间复杂度降至 \(O(\frac{n^2m}{w})\)


例题:

P3389 【模板】高斯消元法
P2455 [SDOI2006] 线性方程组

求解不保证有唯一解的 \(n\) 元线性方程组

UVA1564 Widget Factory
SP2883 WIDGET - Widget Factory

求解模 \(p\) 意义下方程数量不保证等于未知数数量的 \(n\) 元线性方程组

P2447 [SDOI2010] 外星千足虫

求解异或方程组

posted @ 2025-02-26 08:04  nueryim  阅读(14)  评论(0编辑  收藏  举报