zl程序教程

您现在的位置是:首页 >  其它

当前栏目

高斯消元法

高斯消
2023-09-27 14:28:32 时间

模板链接:https://www.luogu.org/problemnew/show/P3389

【模板】高斯消元法

题目背景

Gauss G a u s s 消元

题目描述

给定一个线性方程组,对其求解

输入输出格式
输入格式:

第一行,一个正整数 n n

第二至n+1行,每行 n+1 n + 1 个整数,为 a1,a2an a 1 , a 2 ⋯ a n b b ,代表一组方程。

输出格式:

n行,每行一个数,第 i i 行为xi(保留2位小数)

如果不存在唯一解,在第一行输出”No Solution”.

输入输出样例
输入样例#1:

3
1 3 4 5
1 4 7 3
9 3 2 2

输出样例#1:

-0.97
5.18
-2.39

说明

1n100,|ai|104,|b|104 1 ≤ n ≤ 100 , | a i | ≤ 10 4 , | b | ≤ 10 4

题解

高斯消元法是用来解多元多次方程组的,我们将方程组的各个方程表示为矩阵形式,具体如下:

以下列方程组为例:


 X1+X2+X3=0   X 1 + X 2 + X 3 = 0
2X1+2X2+X3=1 2 X 1 + 2 X 2 + X 3 = 1
 X1+X2X3=1   X 1 + X 2 − X 3 = − 1

写成矩阵形式如下:  

121121111011 1 1 1 0 2 2 1 1 1 1 − 1 − 1

之后,我们每次都考虑用一个方程去消元:

我们用第一个方程消掉第一个未知数,消元后的矩阵如下:


001211 0 − 1 1 0 − 2 − 1

这样消元后,方程数-1,未知数数-1。

在消第二个未知数时,我们发现 x2 x 2 的系数都为0,我们称这样的未知数为自由元。因为系数都为0,我们跳过对 x2 x 2 的消元,矩阵变成下面这样:


1211 − 1 1 − 2 − 1

经过这样消元,未知数的数量-1。

最后一步,我们消去 x3 x 3


0 0

矩阵只剩下0,这样这个方程就是有解的,反之无解。另外,如果有自由元的话这个方程就是有无穷组解的。当没有自由元时该方程有唯一解,此时我们可以将结果逐行代回求解。

代码实现方面,我们只需要模拟以上过程消元即可,单次消元的复杂度是 O(nm) O ( n m ) 的,总消元次数为 O(min(n,m)) O ( m i n ( n , m ) ) ,所以总复杂度为 O(min(n,m)nm) O ( m i n ( n , m ) n m )

代码

每次我们用系数最大的方程消元,利于减小误差。

#include<bits/stdc++.h>
#define eps 1e-8
using namespace std;
const int M=105;
double x[M][M];
int n;
void in()
{
    scanf("%d",&n);
    for(int i=0;i<n;++i)
    for(int j=0;j<=n;++j)
    scanf("%lf",&x[i][j]);
}
void ac()
{
    int pos;
    double ra;
    for(int i=0;i<n;++i)
    {
        pos=i;
        for(int j=i+1;j<n;++j)
        if(fabs(x[pos][i])<fabs(x[j][i]))pos=j;
        if(fabs(x[pos][i])<eps)
        {
            printf("No Solution\n");
            exit(0);
        }
        if(pos!=i)
        for(int j=0;j<=n;++j)swap(x[pos][j],x[i][j]);
        for(int j=i+1;j<n;++j)
        {
            ra=x[j][i]/x[i][i];
            for(int k=i;k<=n;++k)
            x[j][k]-=ra*x[i][k];
        }
    }
    for(int i=n-1;i>=0;--i)
    {
        for(int j=i+1;j<n;++j)x[i][n]-=x[j][n]*x[i][j];
        x[i][n]/=x[i][i];
    }
    for(int i=0;i<n;++i)
    printf("%.2lf\n",x[i][n]);
}
int main()
{
    in();ac();
    return 0;
}