高斯消元详解

题目描述

题目背景
Gauss消元

题目描述

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

输入格式

第一行,一个正整数 n n n

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

输出格式

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

如果不存在唯一解,在第一行输出" N o   S o l u t i o n No\ Solution No Solution".

原题链接:P3389 【模板】高斯消元法

解题思路

我们先来研究研究这个方程组:
{ x 1 + 2 x 2 − x 3 = − 6 2 x 1 + x 2 − 3 x 3 = − 9 − x 1 − x 2 + 2 x 3 = 7 \begin{cases} x_1+2x_2-x_3=-6\\ 2x_1+x_2-3x_3=-9\\ -x_1-x_2+2x_3=7\\ \end{cases} x1+2x2x3=62x1+x23x3=9x1x2+2x3=7
我们可以只看系数,构成一个系数矩阵,然后再加上等号右侧的常数,构成一个增广矩阵

( 1 2 − 1 − 6 2 1 − 3 − 9 − 1 − 1 2 7 ) \left(\begin{array}{ccc|c} 1 & 2 & -1 & -6\\ 2 & 1 & -3 & -9\\ -1 & -1 & 2 & 7\end{array}\right) 121211132697

高斯消元解方程组的方法其实可以概括为增广矩阵的三类操作:

  1. 用一个非0的数乘某一行。
  2. 把其中一行的若干倍加到另一行上。
  3. 交换两行的位置。

这三类操作便称为矩阵的初等行变换

于是,高斯消元的大致思路就是:

  1. 通过“矩阵的初等行变换”,消去系数,使得矩阵呈现三角形,如下:
    ( 1 2 − 1 − 6 0 1 1 1 0 0 1 3 ) \left(\begin{array}{ccc|c} 1 & 2 & -1 & -6\\ 0 & 1 & 1 & 1\\ 0 & 0 & 1 &3\end{array}\right) 100210111613
    即第 n n n行的前 n − 1 n-1 n1个数都是 0 0 0
    这样的矩阵就叫做阶梯型矩阵
    于是,我们可以解得 x 3 = 3 x_3=3 x3=3
  2. 由于第一步中得到了 x 3 x_3 x3的解,所以我们将这个解回代到上一层,便可以求出 x 2 x_2 x2。之后便是再将 x 3 , x 2 x_3,x_2 x3,x2回代,又可以求出 x 1 x_1 x1,于是矩阵可以化为:
    ( 1 0 0 1 0 1 0 − 2 0 0 1 3 ) \left(\begin{array}{ccc|c} 1 & 0 & 0 & 1\\ 0 & 1 & 0 & -2\\ 0 & 0 & 1 &3\end{array}\right) 100010001123
    该矩阵给出了方程的解,叫做简化阶梯矩阵

回代的过程比较简单,所以下面说一说如何进行消元。

来个具体的例子看看:
还是上文的方程组,我们对其进行如下操作:

  • 我们通过一重循环,一列一列地将第 i i i列的 i − 1 i-1 i1个数消去为0。我们首先选择该列绝对值最大的数,并把该行换为第 i i i行。其次,通过这行消去第 i + 1 i+1 i+1 n n n行,即将该列系数化为同一个数,再相减。如下:
    ( 1 2 − 1 − 6 2 1 − 3 − 9 − 1 − 1 2 7 ) \left(\begin{array}{ccc|c} 1 & 2 & -1 & -6\\ 2 & 1 & -3 & -9\\ -1 & -1 & 2 & 7\end{array}\right) 121211132697
    第一列绝对值最大的是2,将这一行换为第一行:
    ( 2 1 − 3 − 9 1 2 − 1 − 6 − 1 − 1 2 7 ) \left(\begin{array}{ccc|c} 2 & 1 & -3 & -9\\1 & 2 & -1 & -6\\ -1 & -1 & 2 & 7\end{array}\right) 211121312967
    与第2行相消,即将第1行的所有数乘上 1 2 \frac{1}{2} 21,再减去第2行:
    ( 2 1 − 3 − 9 2 ⋅ 1 2 − 1 1 ⋅ 1 2 − 2 − 3 ⋅ 1 2 − ( − 1 ) − 9 ⋅ 1 2 − ( − 6 ) − 1 − 1 2 7 ) \left(\begin{array}{ccc|c} 2 & 1 & -3 & -9\\2\cdot\frac{1}{2}-1 & 1\cdot \frac{1}{2}-2 & -3\cdot\frac{1}{2}-(-1) & -9\cdot\frac{1}{2}-(-6)\\ -1 & -1 & 2 & 7\end{array}\right) 2221111121213321(1)29921(6)7
    同理,其他行也可以这么消去。
    接下来,看代码——

参考代码

#include<stdio.h>
#include<iostream>
#define eps 1e-10
using namespace std;

int n;
double g[105][105],ans[105];

double abs(double a) //手写好像更快
{
	return a>0?a:-a;
}

void Gauss()
{
	for(int c=1;c<=n;c++) //一列一列消元
	{
		int r=c;
		for(int i=c+1;i<=n;i++) //找绝对值最大数
			r=abs(g[i][c])>abs(g[r][c])?i:r;
		if(abs(g[r][c])<eps) //坑点!如果最大的数为0(或是接近0),说明该行已经都是0,也说明该方程无解。由于是double运算,可能结果很小但不是0,所以要设置精度
		{
			printf("No Solution\n");
			return;
		}
		if(r!=c) swap(g[c],g[r]); //换行
		double tmp=g[c][c];
		for(int j=c;j<=n+1;j++) g[c][j]/=tmp; //将该行该列系数化为1,方便计算
		for(int i=c+1;i<=n;i++) //相减,消元
		{
			tmp=g[i][c];
			for(int j=c;j<=n+1;j++) g[i][j]-=(g[c][j]*tmp);
		}
	}
	ans[n]=g[n][n+1];
	for(int i=n-1;i>=1;i--) //回代,输出答案
	{
		for(int j=n;j>i;j--) g[i][n+1]-=(ans[j]*g[i][j]);
		ans[i]=g[i][n+1];
	}
	for(int i=1;i<=n;i++) printf("%.2lf\n",ans[i]);
}

int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n+1;j++) scanf("%lf",&g[i][j]);
	Gauss();
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值