这道题目调试的很久,终于解决了,输出了其中的计算的每一步骤的数据,现将其中的易错点集中标注出来
循环以列开始而不是行的原因
- 如果是以行开始的话,那么在判断倒三角的时候,需要判断i,i行是不是为零,如果不是需要列++,有点麻烦
- 方便判断有解与否
判断是否有解的情况
- 行数 == 列数 唯一解
- 行数 < 列数,判断行数的下面,如果此时曾广矩阵的b中有数字不为零,则无解
- 反之有解
将最大值移入每次的行首
a. 作用是避免系数变大,精度较高
个人觉的难点1. 以数字1消灭之后的几行数据的头数字
- 需要增加的倍数 === 需要变化的行数的第一个数字
- 变化的数字是 已经变为数字1的行数,也就是r行
- 需要修改的就是r + 1行到末尾,
- 从前向后遍历会改变第一个数字,所以先保存,或者是从前向后遍历
个人觉的难点2. 化成最简矩阵
- 用最后一行的数据i行,去修改i- 1, i- 2, ···, 直到第0行
- 变化的数字从i 到 i + 1;
- 和上面类似,要么从后向前遍历,要么保存好对应的数字。
#include <iostream>
#include <cmath>
using namespace std;
const int N = 110;
const double eps = 1e-6;
int n;
double a[N][N];
void out()
{
for(int i = 0; i < n; i ++ )
{
for(int j = 0; j < n + 1; j ++ )
cout << a[i][j] << " ";
cout << endl;
}
cout << endl;
}
int gauss()
{
//倒三角
int c, r = 0;
//c是列 可能其中没有数据, r表示的是当前操作的行数,可能有n行,可能没有
for(c = 0; c < n; c ++ )
{
int t = r; //当前列的最大值
for(int i = r; i < n; i ++ )
if(a[i][c] > a[t][c])
t = i;
if(fabs(a[t][c]) < eps) continue;
//然后开始交换
for(int i = c; i <= n; i ++ ) swap(a[r][i], a[t][i]);
for(int i = n; i >= c; i -- ) a[r][i] /= a[r][c];
//开始将该列数据为0
for(int i = r + 1; i < n; i ++ )
{
double k = a[i][c]; //记录的每一行首元素的值, 因为每一行的值会发生改变
if(fabs(k) > eps)
for(int j = c; j <= n; j ++ )
a[i][j] = a[i][j] - a[r][j] * k;
}
r++;
}
//如果最终r没到最后一行,但是列数到了最后一列,此时可能无解,或者多解,
//多解就是b不为0,前面的为0,即从r + 1如果
if(r < n)
{
//r提前加了一个,所以是r++:
for(int i = r; i < n; i ++ )
if(fabs(a[i][n]) > eps)
return 2;
return 1;
}
//开始倒着解决题目,对角线开始依次解决,最后一行解决前n- 1行,依次类推
for(int i = n - 1; i >= 1; i -- )
for(int k = i - 1; k >= 0; k --)
{
double q = a[k][i];
//用第i行解决第k行,第i行乘以第k的第j个元素
for(int j = i ; j <= n; j ++ )
a[k][j] -= a[i][j] * q;
// out();
}
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)
puts("Infinite group solutions");
else
puts("No solution");
return 0;
}