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) 的,高斯消元的基本思想:

  1. 从头开始枚举每一列
  2. 找所有行中这一列绝对值最大的数
  3. 将绝对值最大的数所在的行换到最上面去(这里的最上面指的是没处理过的最上面)
  4. 将这一行第一个a 消成1(这行所有的数全部除第一个数),这里要注意倒着消
  5. 将下面所有行的这一列消成 0(减去a[r][j] * a[i][c] 意为第r行(最上面的一行)第j列 × 这一行第c列(当前枚举的一列),最后就会变成 a[i][c] -= a[r][c] * a[i][c])而 a[r][c] == 1
  6. 根据 r 的值判断是否存在无穷解或无解
  7. 递推出每一个 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 暴风哭泣

posted @ 2020-09-02 18:46  Hayasaka  阅读(92)  评论(0编辑  收藏  举报