不考虑无解、无穷解的情况
(附模板题)
今天我们先从这个最基本的的高斯-约旦消元法谈起。
(之所以不讲最朴素的高斯消元,是因为高斯-约旦消元法相较于它简化了一个回带的过程)
我们先来解一个方程组玩玩!
x-2y+3z=6
4x-5y+6z=12
7x-8y+10z=21
很简单,对吧?
没错,就像小学那样消元(one by one)
为了方便,我们先将它的系数和等式右边的值转化为一个矩阵
1 -2 3 6
4 -5 6 12
7 -8 10 21
为了解这个方程组,我们希望通过加减消元把它变成如下的形式
1 0 0 a
0 1 0 b
0 0 1 c
因为这样我们就可以一眼看出它的解(x=a,y=b,z=c)
那怎么才能变出来呢?消元呗!
这里我们的方法是以列为单位消元。
首先我们将第一列转化为1 0 0的形式。
(注意:我们通常把未处理的方程中系数绝对值最大的一个作为处理对象来减小误差,因为我们待会儿有一个double类型的除法,可能这会儿你还是不懂,没事,待会儿看了代码就懂了)
所以我们先将矩阵变成这样子
7 -8 10 21
4 -5 6 12
1 -2 3 6
然后利用第一行和第二行,消去第二行的第一个元素(使其变成0)。
这里我们的方法是第二行减去第一行的4/7。
就变成了这个
7 -8 10 21
0 -3/7 2/7 0
1 -2 3 6
同理第三行减去第一行的1/7。
7 -8 10 21
0 -3/7 2/7 0
0 -6/7 11/7 3
现在第一列不就变好了吗?继续按照同样的方式对第二列开刀~~
因为在第二行和第三行中,第三行的第二个元素-6/7比第二行的第二个元素-3/7的绝对值大,所以两行交换
7 -8 10 21
0 -6/7 11/7 3
0 -3/7 2/7 0
接着用第一行减去第二行的-8/(-6/7),即28/3,然后用第三行减去第二行的(-3/7)/(-6/7),即1/2。
7 0 -14/3 -7
0 -6/7 11/7 3
0 0 -1/2 -3/2
现在第二列不也变好了吗?继续按照同样的方式对第三列开刀~~
先用第一行减去第三行的(-14/3)/(-1/2),即28/3,然后用第二行减去第三行的(11/7)/(-1/2),即-22/7。
7 0 0 7
0 -6/7 0 -12/7
0 0 -14/3 -14
好了,现在最后剩下的任务就是解如下的这个方程组了
7x+0y+0z=7
0x+(-6/7)y+0z=-12/7
0x+0y+(-14/3)z=-14
这个大家都会解吧!用每行等式右边的值除以该行的非零系数
最后我们就得到了一组解x=1,y=2,z=3。
(所以高斯消元其实是运用了小学解方程组的加减法的呢。)
还有点儿昏?正常,本人表述不清。
看看代码吧!
Code
#include<bits/stdc++.h>
using namespace std;
const int MAX=120;
const double eps=1e-8;//比较double类型大小时,用于控制精度
int n;
double Matrix[MAX][MAX];//存储系数和等式右边的常数
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n+1;j++) scanf("%lf",&Matrix[i][j]);
}
for(int i=1;i<=n;i++)
{
int t=i;
for(int j=i+1;j<=n;j++)
{
if(fabs(Matrix[j][i])>fabs(Matrix[t][i])) t=j;//选取未处理行i列上系数绝对值最大的
}
if(t!=i)//交换两行
{