AcWing 883 - 高斯消元解线性方程组(高斯消元)
输入一个包含n个方程n个未知数的线性方程组。
方程组中的系数为实数。
求解这个方程组。
下图为一个包含m个方程n个未知数的线性方程组示例:
输入格式
第一行包含整数n。
接下来n行,每行包含n+1个实数,表示一个方程的n个系数以及等号右侧的常数。
输出格式
如果给定线性方程组存在唯一解,则输出共n行,其中第i行输出第i个未知数的解,结果保留两位小数。
如果给定线性方程组存在无数解,则输出“Infinite group solutions”。
如果给定线性方程组无解,则输出“No solution”。
数据范围
1≤ n ≤100
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
题目大意:
先输入一个 n ,表示有 n 个未知数,接下来有 n 行,表示有 n 个线性方程,每次输入为浮点数,格式为a1x1 + a2x2 + … akxk = ni ,你要输入的是a1…ak 和 ni ,如果方程只有一组解,则第 i 行输出一个 Xi 保留两位小数,如果无解或有无穷组解则输出相应的提示。
解题思路:
高斯消元模板题,用一个二维数组存储增广矩阵,复杂度是O(n3) 的,高斯消元的基本思想:
- 从头开始枚举每一列
- 找所有行中这一列绝对值最大的数
- 将绝对值最大的数所在的行换到最上面去(这里的最上面指的是没处理过的最上面)
- 将这一行第一个a 消成1(这行所有的数全部除第一个数),这里要注意倒着消
- 将下面所有行的这一列消成 0(减去a[r][j] * a[i][c] 意为第r行(最上面的一行)第j列 × 这一行第c列(当前枚举的一列),最后就会变成 a[i][c] -= a[r][c] * a[i][c])而 a[r][c] == 1
- 根据 r 的值判断是否存在无穷解或无解
- 递推出每一个 x 的值
Code:
#include <iostream>
#include <cmath>
using namespace std;
const int N = 110;
const double eps = 1e-6;
double a[N][N];//用于存放增广矩阵
int n;
int gauss()
{
int r, c;//r 行 c 列,从第1列枚举到 n - 1 列
for (r = 0, c = 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[t][c]) < eps) continue;//满足这个条件说明该列所有数都是0,因为最大绝对值是0
for (int i = c; 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;//这种情况是 n(系数) = 0的情况,一定无解
return 1;//反之则是无穷组解
}
//如果走到这里说明有一组唯一解
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];//递推出来每一个x 的值,这里自己动手模拟一下就懂了
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 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;
}
PS : 高斯消元比较好理解 过程也很简单 不过代码写了两个晚上才过,太绕了 T.T 暴风哭泣