【数学】高斯消元

1. 算法简介#

高斯消元法(Gauss–Jordan elimination)是求解线性方程组的经典算法。

例如求解下列方程组:

{2x+9y5z=104x+20y+z=24x2y+3z=8

形式化的,高斯消元可用于求解类似于

{a1,1x1+a1,2x2++a1,nxn=b1a2,1x1+a2,2x2++a2,nxn=b2an,1x1+an,2x2++an,nxn=bn

的方程组。

2. 算法理论#

2.1 高斯消元#

先将线性方程组转化为矩阵:

[a1,1a1,2a1,nb1a2,1a2,2a2,nb2an,1an,2an,nbn]

显然为一个 n×(n+1) 的矩阵。

我们希望将它消成上三角的形式,如下:

[w1,1w1,2w1,nB10w2,2w2,nB200an,nBn]

我们可以枚举对角线,依次将对角线下面的所有数消成 0

例如第一次操作利用 a1,1a2,1,a3,1an,1 消成 0

[a1,1a1,2a1,nb1a2,1a2,1a1,1a1,1a2,2a2,1a1,1a1,1a2,nan,1a1,1a1,1b2a2,1a1,1a1,1an,1an,1a1,1a1,1an,2an,1a1,1a1,1an,nan,1a1,1a1,1bnan,1a1,1a1,1]

变成:

[a1,1a1,2a1,nb10a2,2a2,1a1,1a1,1a2,nan,1a1,1a1,1b2a2,1a1,1a1,10an,2an,1a1,1a1,1an,nan,1a1,1a1,1bnan,1a1,1a1,1]

依次类推消掉下三角的所有数,消成上三角的形式:

[w1,1w1,2w1,nB10w2,2w2,nB200an,nBn]

然后回带,依次相减。消成对角线的形式:

[W1,100C10W2,20C200Wn,nCn]

则答案 xi=BiWi,i.

判断解的情况:

  1. i 使得 Wi,i=0Ci0,则方程组无解;
  2. i 使得 Wi,i=0Ci=0,则方程组有无数解;

误差处理:

  1. 由于误差传递,要将 ai,i=0 写成 fabs(ai,i)<0;
  2. 为了减小误差,每次将小的数除以大的数再去消元;

2.1 高斯-约旦消元#

对于矩阵

[a1,1a1,2a1,nb1a2,1a2,2a2,nb2an,1an,2an,nbn]

枚举对角线 (i,i),找到 ai,i0 的一行,交换至第一行,依次消元;

高斯消元为每一次往下消元,而高斯-约旦消元为每一次将除本行的其他行全部消元。

由于每一次都会将除对角线外的所有数消成 0,所以高斯-约旦消元后只剩下了

[W1,100C10W2,20C200Wn,nCn]

不需要高斯消元的回带过程。

3. 算法实现#

luoguP3389 【模板】高斯消元法#

高斯消元模板

#include<bits/stdc++.h>
#define int long long
#define For(i,l,r) for(int i=l;i<=r;++i)
#define FOR(i,r,l) for(int i=r;i>=l;--i)
#define eqs 1e-7

using namespace std;

const int N = 1e3 + 10;

int n;

double a[N][N];

signed main() {
  ios::sync_with_stdio(0);
  cin.tie(0), cout.tie(0);
  cin >> n;
  For(i,1,n) {
    For(j,1,n+1) {
      cin >> a[i][j];
    }
  }
  for (int i = 1; i <= n - 1; ++i) {
    For(j,i+1,n) if(fabs(a[i][i]) < fabs(a[j][i])) swap(a[i], a[j]);
    if(fabs(a[i][i]) < eqs) continue;
    For(j,i+1,n) {
      double w = a[j][i] / a[i][i];
      For(l,i,n+1) {
        a[j][l] -= w * a[i][l];
      }
    }
  }
  for (int i = n; i >= 2; --i) {
    if(fabs(a[i][i]) < eqs) continue;
    FOR(j,i-1,1) {
      double w = a[j][i] / a[i][i];
      For(l,i,n+1) {
        a[j][l] -= w * a[i][l];
      }
    }
  }
  For(i,1,n) {
    int cnt0 = 0;
    For(j,1,n) {
      cnt0 += (a[i][j] == 0);
    }
    if(cnt0 == n) return puts("No Solution"), 0;
  }
  For(k,1,n) {
    printf("%.2lf\n", a[k][n+1] / a[k][k]);
  }
  return 0;
}

/*
9 3       2         2 
0 3.66667 6.77778   2.77778 
0 0       -1.15152  2.75758 


9 0       2         -13.5526 
0 3.66667 0         19.0088 
0 0       -1.15152  2.75758
 */

luoguP2455 [SDOI2006] 线性方程组#

高斯-约旦模板。

高斯消元的华点在于这样一组样例:

4
0 0 1 1 2
0 0 1 0 1
0 0 0 1 1
0 0 0 0 0
0

直接用高斯消元模板会出现对角线全 0 而无法消元的情况。

#include<bits/stdc++.h>
#define ll long long
#define For(i,l,r) for(int i=l;i<=r;++i)
#define FOR(i,r,l) for(int i=r;i>=l;--i)
#define eps 1e-9

using namespace std;

const int N = 55;

int n;

double a[N][N];

bool st[N];

signed main() {
  ios::sync_with_stdio(0);
  cin.tie(0), cout.tie(0);
  cin >> n;
  For(i,1,n) {
    For(j,1,n+1) {
      cin >> a[i][j];
    }
  }
  For(i,1,n) {
    For(j,1,n) if(fabs(a[i][i]) < fabs(a[j][i]) && !st[j]) swap(a[i], a[j]), swap(st[i], st[j]);
    if(fabs(a[i][i]) < eps) continue;
    st[i] = 1;
    For(j,1,n) {
      if(i == j) continue;
      double w = a[j][i] / a[i][i];
      For(l,1,n+1) {
        a[j][l] -= w * a[i][l];
      }
    }
  }
  For(i,1,n) if(fabs(a[i][i]) < eps && fabs(a[i][n+1]) > eps) return puts("-1"), 0; 
  For(i,1,n) if(fabs(a[i][i]) < eps && fabs(a[i][n+1]) < eps) return puts("0"), 0;
  For(k,1,n) {
    printf("x%d=%.2lf\n", k, a[k][n+1] / a[k][k]);
  }
  return 0;
}

作者:Daniel-yao

出处:https://www.cnblogs.com/Daniel-yao/p/18308249

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

posted @   Daniel_yzy  阅读(163)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
more_horiz
keyboard_arrow_up dark_mode palette
选择主题
menu
点击右上角即可分享
微信分享提示