题目链接 : 点击查看
题目描述 :
输入一个包含 n 个方程 n 个未知数的线性方程组。
方程组中的系数为实数。
求解这个方程组。
下图为一个包含 m 个方程 n 个未知数的线性方程组示例:
输入输出格式 :
输入
第一行包含整数 n。
接下来 n 行,每行包含 n+1 个实数,表示一个方程的 n 个系数以及等号右侧的常数。
输出
如果给定线性方程组存在唯一解,则输出共 n 行,其中第 i 行输出第 i 个未知数的解,结果保留两位小数。
如果给定线性方程组存在无数解,则输出 Infinite group solutions。
如果给定线性方程组无解,则输出 No solution。
输入输出样例 :
输入
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个未知数的多元线性方程组。具体的算法步骤如下。
列举每一列c
- 找到当前列绝对值最大的那一行
- 将该行换到最上面
- 将该行第一个数变成1
- 将下面所有行的当前列消成0
- 如此进行到最后再从下向上进行消元
详见如下代码。
代码 :
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
const int N = 110;
const double eps = 1e-6;
int n;
double a[N][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[t][c]) < eps) continue;//最大值为0说明所有数都为0,之前存在这一列的约数方程
for (int i = c; i < n + 1; 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 ++ ) {//将当前列的所有数消成0
if (fabs(a[i][c]) > eps) {
for (int j = n; j >= c; j -- ) {
a[i][j] -= a[r][j] * a[i][c];
}
}
}
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 + 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) cout << "Infinite group solutions" << endl;
else cout << "No solution" << endl;
return 0;
}
下面我们给出高斯消元的模板
// a[N][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[t][c]) < eps) continue;
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 ++ ) // 用当前行将下面所有的列消成0
if (fabs(a[i][c]) > eps)
for (int j = n; j >= c; j -- )
a[i][j] -= a[r][j] * a[i][c];
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[i][j] * a[j][n];
return 0; // 有唯一解
}