题目描述:
输入一个包含n个方程n个未知数的线性方程组。方程组中的系数为实数。求解这个方程组。
下图为一个包含m个方程n个未知数的线性方程组示例:
输入格式
第一行包含整数n。
接下来n行,每行包含n+1个实数,表示一个方程的n个系数以及等号右侧的常数。
输出格式
如果给定线性方程组存在唯一解,则输出共n行,其中第i行输出第i个未知数的解,结果保留两位小数。
如果给定线性方程组存在无数解,则输出“Infinite group solutions”。
如果给定线性方程组无解,则输出“No solution”。
数据范围
1≤n≤100,
所有输入系数以及常数均保留两位小数,绝对值均不超过100。
输入样例:
3
1.00 2.00 -1.00 -6.00
2.00 1.00 -3.00 -9.00
-1.00 -1.00 2.00 7.00
输出样例:
1.00
-2.00
3.00
分析:
本题是要我们实现线性代数里面的高斯消元求解线性方程组,我们往往先把增广矩阵化为行阶梯型,然后再自下而上求解各个变量。在线代里,我们往往先找第一列为1的某行,将其换到第一行,然后用该行将其它行第一列都化为0,紧接着再考虑第二列。在编程过程中,我们往往先找到某列中非零的数x所在行作为第一行(这里y总是找到该列最大的数,感觉没啥必要),也就是与当前变换的第一行交换,然后将第一行都除以x,将x化为1,再去将下面各行该列都化为0.当所有的增广矩阵都化为行阶梯型后,判断下秩的大小,本题的系数矩阵是n*n的方阵,故满秩时,有唯一解,从最后一行开始自底而上将上面各列的系数都化为0,最后留下的常数列就是方程的解;如果系数矩阵不满秩,则判断下面的行常数列是否都是0,不是说明系数矩阵的秩不等于增广矩阵的秩,方程无解,否则有无穷多解。
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
const int maxn = 105;
const double eps = 1e-6;
double a[maxn][maxn];
int n;
int gauss(){
int c,r;
for(c = 0,r = 0;c < n;c++){
int t = r;
for(int i = r;i < n;i++){
//if(fabs(a[i][c]) > fabs(a[t][c])) t = i;
if(fabs(a[i][c]) > eps){//找到该列非0的数
t = i;
break;
}
}
if(fabs(a[t][c]) < eps) continue;//该列都是0,直接执行下一列
for(int i = 0;i <= n;i++) swap(a[t][i],a[r][i]);//交换到最上面
for(int i = n;i >= c;i--) a[r][i] /= a[r][c];//最上面一行首个非零数化1
for(int i = r + 1;i < n;i++){
if(fabs(a[i][c]) > eps){//非零
for(int j = n;j >= c;j--) a[i][j] -= a[r][j] * a[i][c];//化0
}
}
r++;
}
if(r < n){
for(int i = r;i < n;i++){
if(fabs(a[i][n]) > eps) return 2;
}
return 1;
}
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];
}
}
return 0;
}
int main(){
cin>>n;
for(int i = 0;i < n;i++){
for(int j = 0;j <= n;j++){
cin>>a[i][j];
}
}
int res = gauss();
if(res == 0){
for (int i = 0; i < n; i ++ ) printf("%.2lf\n", a[i][n]);
}
else if(res == 1) puts("Infinite group solutions");
else puts("No solution");
return 0;
}