高斯消元解线性方程组
思路:
(1)模拟线性代数解方程组办法,在此讨论正方形方程组求解。
(2)考虑几个问题:
- 数据存储:采用double数组存储。
- 判断是否为零,由于double计算存在误差,采用const double = eps = 1e-6;通过绝对值与eps比较判断是否为0。
(3)算法流程:
- 逐列枚举,行也从0开始枚举;
- 对于第c列,从第r行开始,找到绝对值最大的行号t;
- 如果a[t][c]为0,即该列最大值为0,则该列非固定行值均为0,跳过该列操作(因为不能让该列出现1个1);
- 令第c列绝对值最大行与第r行调换位置。
- 将r行第c列元素归一。
- 用该列的1将r行以下的元素全部消为0;
- 此时保证出现一个1了,所以r++;(显然r的数量就是1的数量)
- 除b列所有列用完后,判定r是否小于n;
- 如果小于n,说明1的个数小于n个,说明无解或者存在冗余项,此时做一判断,从r行到n-1行的b值逐个判断,如果出现非0项,由于左边r行及以下全部为0,若b不为0,则一定无解;如果都为0,则存在冗余项,有多组解。
- 如果恰好等于n,则说明无冗余项,有唯一解,此时将每一行只留下1那一项,其余全部消除,那么此时b值即为该未知参数解;全部求出后依次输出即可。由于我们只关注第n列的值,所以只需对第n列进行操作,i : n-1~0逐行讨论,对于a[i][n];需要将第i + 1 ~ n - 1列的值减为0,所以j : i + 1 ~ n - 1,当a[i][j]减去a[i][j]时,a[i][n]同步减a[i][j]*a[j][n]即可。
(4)注意:用绝对值判定。
代码:
#include<bits/stdc++.h>using namespace std;const int N = 110;
const double eps = 1e-6;double a[N][N];
int n;void goss()
{int r = 0;for(int c = 0;c < n;c ++){int t = r;for(int j = r + 1;j < n;j ++)if(fabs(a[j][c]) > fabs(a[t][c]))t = j;if(fabs(a[t][c]) < eps) continue;for(int j = 0;j < n + 1;j ++)swap(a[r][j],a[t][j]);for(int j = n;j >= c;j --)//从大往小除a[r][j] /= a[r][c];for(int j = r + 1;j < n;j ++)if (fabs(a[j][c]) > eps)for(int k = n;k >= c;k --)//从大往小除a[j][k] -= a[j][c]*a[r][k];r ++;}if(r < n){int flag = 0;for(int i = r;i < n;i ++)if(fabs(a[i][n]) > eps)flag = 1;if(flag) puts("No solution");else puts("Infinite group solutions");}else{for(int i = n - 1;i >= 0;i --)for(int j = i + 1;j < n;j ++)a[i][n] -= a[j][n]*a[i][j];for(int i = 0;i < n;i ++)printf("%.2lf\n",a[i][n]);}
}int main()
{cin >> n;for(int i = 0;i < n;i ++)for(int j = 0;j < n + 1;j ++)cin >> a[i][j];goss();return 0;
}