前言
大一刚刚学习了线性代数,我们都知道线代中最容易出错的就是计算,那我们用计算不会出错的计算机来求解这个线性方程组是一个怎样的体验呢?
一、什么是高斯消元?
高斯消元法(或译:高斯消去法),是线性代数规划中的一个算法,可用来为线性方程组求解。
二、算法思路
1.要求解的例题
输入一个包含n个方程n个未知数的线性方程组。
方程组中的系数为实数。
求解这个方程组。
输入:
第一行两个整数n(1 < n < 100)
后n行输入一个n*(n + 1)的增广矩阵
输出:
答案共n行表示x1~xn(保留两位小数,当无解或有无穷多组解时输出相应提示)
2.详细思路
首先分析解的情况:我们都知道线性方程组有三种解的情况,我们在此仅计算有唯一解的答案,当我们遇到无解或者无穷多组解时输出相应提示。
求解方程组时,我们要把方程化为最简形,而我们的算法就是要实现此过程。
消元时,首先找到适合的一行交换到当前所计算的一行,并将该行首列之下全跟新为0,重复操作直到最后一行或出现非唯一解情况。
//记当前修改到了r行c列
int t = r;//暂时存储所修改到的行数
for(int i = r + 1; r <= n; i ++ )
if(fabs(a[i][c]) > fabs(a[t][c]))
t = i;//找到未修改的第c列最大值的行
for(int i = c; i <= n + 1; i ++ )
swap(a[t][i], a[r][i]);//交换第r行与第t行
for(int i = n; i >= c; i ++ )
a[r][i] /= a[r][c];//将第r行首非零数字跟新为1
for(int i = r + 1; i <= n; i ++ )
if(fabs(a[i][c]) > eps) // eps 表示一个很小的值,因为c++浮点数存储原因,不能直接判断是否为零
for(int j = n; j >= c; j -- )
a[i][j] -= a[i][c] * a[r][j];
当跟新到最后一行时,再依次计算x的值并返回上一行进行计算。
for(int i = n - 1; i >= 1; i -- )
for(int j = i + 1; j <= n; j ++ )
a[i][n + 1] -= a[i][j] * a[j][n + 1];
三、代码展示
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
const int N = 110;
const double eps = 1e-9;
double a[N][N];
int n;
int gauss(){
int r, c;
for(r = 1, c = 1; c <= n; c ++ ){
int t = r;
for(int i = r + 1; i <= n; i ++ )
if(fabs(a[i][c]) > fabs(a[t][c]))t = c;
if(fabs(a[t][c]) < eps)continue;
for(int i = c; i <= n + 1; i ++ )swap(a[r][i], a[t][i]);
for(int i = n + 1; i >= c; i -- )a[r][i] /= a[r][c];
for(int i = r + 1; i <= n; i ++ )
if(fabs(a[i][c]) > eps)
for(int j = n + 1; j >= c; j -- )
a[i][j] -= a[i][c] * a[r][j];
r ++ ;
}
if(r <= n){
for(int i = r; i <= n ; i ++ )
if(fabs(a[r][n + 1]) > eps)return 1;
return 2;
}
for(int i = n - 1; i >= 1; i -- )
for(int j = i + 1; j <= n; j ++ )
a[i][n + 1] -= a[i][j] * a[j][n + 1];
return 0;
}
int main()
{
cin >> n;
for(int i = 1; i <= n; i ++ )
for(int j = 1; j <= n + 1; j ++ )cin >> a[i][j];
int t = gauss();
if(t == 0)
for(int i = 1; i <= n; i ++ )printf("%.2lf\n", a[i][n + 1]);
else if(t == 1)puts("无解");
else puts("有无穷多组解");
return 0;
}