高斯消元 (NEW)
作者:
橙外
,
2021-06-08 11:19:38
,
所有人可见
,
阅读 289
枚举每一列
1.找到该列系数绝对值最大的一行
2.将该行置顶
3.将该行该列的系数变成$1$
4.将下面所有行的该列系数消为$0$
最后至下往上解方程
三种结果:
1.完美阶梯形$=>$唯一解
2.$0=$非零数$=>$无解
3.$0=0$$=>$无穷解
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
const int N = 110;
const double eps = 1e-8;
int n;
double a[N][N];
int gauss()
{
int r, c;
for (c = 0, r = 0; c < n; c ++) // 枚举每一列c
{
// 找到第c列系数绝对值最大的一行,编号为t
int t = c;
for (int i = r; i < n; i ++)
if (fabs(a[i][c]) > fabs(a[t][c]))
t = i;
// 如果每一行的第c列系数都为0,那就不需要继续了
if (fabs(a[t][c]) < eps) continue;
// 把第t行置顶
for (int i = c; i <= n; i ++) swap(a[t][i], a[r][i]);
// 然后把置顶的行的第c列系数变成1(需要从后往前循环)
for (int i = n; i >= c; i --) a[r][i] /= a[r][c];
// 然后把除顶行外的所有行的第c列系数变成0
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[i][c] * a[r][j];
// 顶行已处理完毕,可以继续循环了
r ++;
}
// 如果行数小于n,那么肯定是有 常数 = 0 的方程
if (r < n)
{
for (int i = r; i < n; i ++) // 如果有 非零数 = 0 的方程说明无解
if (fabs(a[i][n]) > eps)
return 2;
return 1; // 否则都是 0 = 0 的方程,说明有无数多个解
}
// 要从下往上依次解方程(为了简便可以只处理等式右边的数)
for (int i = n - 1; i >= 0; i --)
for (int j = i + 1; j < n; j ++)
a[i][n] -= a[i][j] * a[j][n];
return 0;
}
int main()
{
scanf ("%d", &n);
for (int i = 0; i < n; i ++)
for (int j = 0; j < n + 1; j ++)
scanf ("%lf", &a[i][j]);
int t = gauss();
if (t == 2) puts("No solution");
else if (t == 1) puts("Infinite group solutions");
else
{
for (int i = 0; i < n; i ++)
printf ("%.2lf\n", a[i][n]);
}
return 0;
}