前言:
在一次学校hu测中,
遇到一道正解不用高斯消元,但是部分分需要的中档题
用舒老师的话说,只要是会高斯消元和树形dp
乱搞一下那道题就可以水到70
所以还是学习一下这个很有用算法:高斯消元
简介
数学上,高斯消元法(或译:高斯消去法),是线性代数中的一个算法,
可用来为线性方程组求解,求出矩阵的秩,以及求出可逆方阵的逆矩阵。
当用于一个矩阵时,高斯消元法会产生出一个“行梯阵式”。
高斯消元法可以用在电脑中来解决数千条等式及未知数。
不过,如果有过百万条等式时,这个算法会十分费时。一些极大的方程组通常会用迭代法来解决。
亦有一些方法特地用来解决一些有特别排列的系数的方程组。
手玩
高斯消元简单来说就是我们平时的解方程
然而我在简介中提到了一个“行梯阵式”
行梯矩阵
指一个矩阵每个非零行的非零首元都出现在上一行非零首元的右边,
同时没有一个非零行出现在零行之下。
如:
1 3 0 1
0 2 1 0
0 0 0 1
我们还是稍微来看一下手玩版的高斯消元
下面的是咱们要求解的线性方程组,先把四个方程编上序号。
先把第一行乘以1/2,然后把第一行的相应倍数加到第二、三、四行上。
再把第二行乘以-2,接着将其相应的倍数加到第三、四行上,然后把第三行乘以-1/6。
将第三行的二倍加到第四行上,再把第四行乘以3/7。
然后往回代,就是把第四行的相应倍数加到第一、第二、第三行上;
把第三行的相应倍数加到第一、第二行上。
再把第二行的相应倍数加到第一行上,最后根据得出的矩阵列出方程组,解得最后的解。
总结上面过程,高斯消元法其实就是下面非常简单的过程
原线性方程组 ——> 高斯消元法 ——> 下三角或上三角形式的线性方程组 ——> 前向替换算法求解(对于上三角形式,采用后向替换算法)
转换为行阶梯阵,判断解的情况。
① 无解
当方程中出现(0, 0, …, 0, a)的形式,且a != 0时,说明是无解的。
② 唯一解
条件是k = equ,即行阶梯阵形成了严格的上三角阵。利用回代逐一求出解集。
③ 无穷解。
条件是k < equ,即不能形成严格的上三角形,自由变元的个数即为equ – k,但有些题目要求判断哪些变元是不确定的。
这里单独介绍下这种解法:
首先,自由变元有var - k个,即不确定的变元至少有var - k个。
我们先把所有的变元视为不确定的。
在每个方程中判断不确定变元的个数,如果大于1个,则该方程无法求解。
如果只有1个变元,那么该变元即可求出,即为确定变元。
程序实现
bool guass()
{
int now=1,to;
double t;
for (int i=1;i<=n;i++) //枚举未知量
{
for (to=now;to<=n;to++)
if (fabs(a[to][i])>eps) break;
if (to>n) continue;
if (to!=now)
for (int j=1;j<=n+1;j++)
swap(a[to][j],a[now][j]);
t=a[now][i];
for (int j=1;j<=n+1;j++) a[now][j]/=t; //系数化为一
for (int j=1;j<=n;j++)
if (j!=now)
{
t=a[j][i];
for (int k=1;k<=n+1;k++)
a[j][k]-=t*a[now][k];
}
now++;
}
for (int i=now;i<=n;i++)
if (fabs(a[i][n+1])>eps) return 0;
return 1;
}
我尝试这解释一下这个函数是怎么发挥作用的:
我们要调用这个函数的前提是我们已经有了一个阵式
for (int i=1;i<=n;i++) //枚举未知量
实际上就是模拟手玩过程中一行一行进行消元
(第i行消掉的一定是第i个未知量)
变量now和to:
因为我们最后计算出来的一定是行阶阵式
now记录的就是当前行从左起第一个非零元素的位置
for (to=now;to<=n;to++)
if (fabs(a[to][i])>eps) break;
找到未处理的方程中,第now个未知量的系数不为零的方程
(这些方程是需要消元的)
t=a[now][i];
for (int j=1;j<=n+1;j++) a[now][j]/=t; //系数化为一
方程的所有系数都除以t
以此为基准进行之后的消元
for (int j=1;j<=n;j++)
if (j!=now)
{
t=a[j][i];
for (int k=1;k<=n+1;k++)
a[j][k]-=t*a[now][k];
}
now++;
其余的每一行进行消元
完成之后now++
相当于整个方程组减少了一个未知量
for (int i=now;i<=n;i++)
if (fabs(a[i][n+1])>eps) return 0;
最后有一个很简单的判断
看一下是不是唯一解