总结:高斯消元
总结:高斯消元
\(O(n^2m)\) 求解 \(n\) 元线性方程组 + 判断解的情况(可以是模意义下)
\(O(\frac{n^2m}{w})\) 求解 \(n\) 元异或方程组 + 判断解的情况
求解有唯一解的 \(n\) 元线性方程组
#1:高斯消元法
这里总结一下,对于一个有唯一解的增广矩阵,高斯消元分 5 步:
- 找主元
- 将当前行的方程主元系数化为一
- 将当前行以下的方程消去主元
- 如果还有别的主元,回到 1
- 对于消完的上三角矩阵一行行回带
版子:
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
版子:
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\) 元线性方程组
求解异或方程组