高斯消元解线性方程组

文章目录

    • 基础知识
    • 算法步骤
    • 举个例子模拟一下算法
    • 例题和代码

基础知识

高斯消元可以通过初等行列变化把 增广矩阵 转换成 阶梯型矩阵,进而求解 n 个线性方程组的解,其时间复杂为 O(n^3)

初等行列变换:(对一个方程组进行以下三个操作不会影响方程的解)

  • 把某一行乘一个非0的数(方程左右两边同乘)
  • 交换某两行的位置
  • 把某一行的若干倍加到另一行上

例如线性方程组为:

a11x1 + a12x2 + a13x3 + … + a1nxn = b1
a21x1 + a22x2 + a23x3 + … + a2nxn = b2

an1x1 + an2x2 + an3x3 + … + annxn = bn

则增广矩阵为:

a11  a12  a13 ...  a1n  b1
a21  a22  a23 ...  a2n  b2
              .       
              .
              .
a21  a22  an3 ...  ann  bn

经过三种初等行列变换,上面的增广矩阵就可以形成一个阶梯型矩阵:

a11  a12  a13 ...  a1n  b1
     a22  a23 ...  a2n  b2
              .       
              .
              .
                    ann  bn

算法步骤

枚举每一列 c:
① 找到列 c 绝对值最大的一行
② 将该行换到最上面
③ 将该行第一个数变成 1 (即第 c 列的数变成 1)
④ 将下面所有行第 c 列消成 0

每枚举一列,都能将一行换到最上面(绝对值最大为 0 除外),换到最上面说明当前这行已经固定了,所以,下次枚举某一列时,将绝对值最大的那一行换到最上面时(即②步骤),并不是换到第一行,而是换到没有固定的行的最上面,同样,步骤①也是在未固定的行中找绝对值最大的。

答案有三种解
如果经过以上步骤得到的是一个完美阶梯型矩阵(即得到 n 个唯一方程,即每个方程不会被另一个方程表示出来),说明有唯一解。

如果转换后出现 0==0 的方程,说明这个方程可以被其他方程表示出来,说明有 多组解。(n元方程组要想有唯一解,需要有n个唯一的方程)

如果转换后出现 0==非0 的方程,说明无解


举个例子模拟一下算法

若方程组为:
x1 + 2x2 - x3 = -6
2x1 + x2 - 3x3 = -9
-x1 - x2 + 2x3 = 7

则增广矩阵为:

1  2  -1  -6
2  1  -3  -9
-1  -1  2  7

枚举第 1 列:

① 找到第 1 列绝对值最大的一行
高斯消元解线性方程组_第1张图片

② 将该行换到最上面
高斯消元解线性方程组_第2张图片
③ 将该行第一个数变成 1(即第 1 列)
注:橙色字体为已经固定的行
高斯消元解线性方程组_第3张图片
④ 将下面所有行第 1 列消成 0
高斯消元解线性方程组_第4张图片
枚举第 2 列:
① 找到第 2 列绝对值最大的一行
高斯消元解线性方程组_第5张图片
② 将该行换到最上面

该行其实已经在未固定行中的最上面了
高斯消元解线性方程组_第6张图片
③ 将该行第一个数变成 1(即第 2 列)
高斯消元解线性方程组_第7张图片

④ 将下面所有行第 c 列消成 0
高斯消元解线性方程组_第8张图片
枚举第 3 列:
① 找到第 3 列绝对值最大的一行
高斯消元解线性方程组_第9张图片
② 将该行换到最上面

该行其实已经在未固定行中的最上面了
高斯消元解线性方程组_第10张图片
③ 将该行第一个数变成 1 (即第 c 列的数变成 1)
高斯消元解线性方程组_第11张图片
④ 将下面所有行第 c 列消成 0
这一行已经是最后一行了,没有下面的行了

枚举完所有列后,我们发现这个矩阵是完美阶梯矩阵,说明是有唯一解的
高斯消元解线性方程组_第12张图片
确定有唯一解后,从最后一行开始向上回代,第三行直接可求出 x3 = 3,然后将 x3 回代到第二行,求出 x2 = -2,再将 x1、x2 回代到第一行,求出 x1 = 1。
综上
x1 = 1
x2 = -2
x3 = 3


例题和代码

AcWing 883. 高斯消元解线性方程组
高斯消元解线性方程组_第13张图片

#include
#include
using namespace std;
const int N = 105;
const double eps = 1e-6; //如果 x < eps,就说明 x 是等于0的 
int n;
double a[N][N];

int gauss()
{
     
   int c, r; // c 是列数、r 是行数
   for(c = 0, r = 0; c < n; c++) //枚举每一列 
   {
     
   	  int t = r;
   	  for(int i=r; i<n; i++) // 找到第 c 列的值最大的是哪一行 
   	   if(fabs(a[i][c]) > fabs(a[t][c]))
   	    t = i;
   	    
   	  if(fabs(a[t][c]) < eps) continue; //当前这一列最大值都为 0,说明这一列所有系数都为0
	   
	   for(int i=c; i<=n; i++) swap(a[t][i],a[r][i]); //把绝对值最大的这行(即第t行)换到当前最上面去(第r行)
	   
	   for(int i=n; i>=c; i--) a[r][i] /= a[r][c]; //把第t行第一个数变成1(方程所有数同除第一个数即可)
	                                               //要先处理最后一个数,因为如果先处理第一个数,第一个数先变为1了,后面所有数就会都除1而不是第一个数
												 
       for(int i =r+1; i<n; i++) //枚举从 r+1 的每一行,把第 c 列的数全部消成 0 
	      if(fabs(a[i][c]) > eps) //如果已经 ==0 ,就不用消了
		    for(int j=n; j>=c; j--) //枚举这一行的每个数 
			  a[i][j] -= a[r][j] * a[i][c]; //每个数减去a[i][c] * a[r][j] 即可 
		  												   
		r++; //该下一行了										   	   
   }
   
   if(r < n) //说明剩下的方程数小于 n 个,需要判断是 无解 还是 有多组解 
   {
      //现在已经是阶梯型,所有系数都应该为0,如果等式右边a[i][n] != 0,说明无解 
   	  for(int i=r; i<n; i++)
   	    if(fabs(a[i][n]) > eps)
   	      return 2;  //无解
   	  return 1; //多组解,说明 r~n-1的这些方程是可以被 0~n 的某些方程表示出来的
		   
   }
   
   //有唯一解,从下向上回代,依次求解 
   for(int i=n-1; i>=0; i--) //从下向上枚举每一行 
     for(int j=i+1; j<n; j++) 
       a[i][n] -= a[i][j] * a[j][n];
   
   return 0;   
} 

int main()
{
     
   	cin >> n;
   	for(int i=0; i<n; i++)
   	 for(int j=0; j<n+1; j++)
   	   cin >> a[i][j];
   	   
   	int t = gauss();
	if(t == 0) //有唯一解 
	{
     
		for(int i=0; i<n; i++) printf("%.2lf\n",a[i][n]);
	}      
	else if(t == 1) printf("Infinite group solutions\n"); //有多组解
	else printf("No solution\n"); //无解 
} 

你可能感兴趣的:(#,算法:数学知识,高斯消元,数论,算法)