【模板】高斯消元法

题目

洛谷P3389高斯消元法

题解

通过初等行变换把增广矩阵变为简化阶梯形矩阵的线性方程组求解算法就是高斯消元算法。

算法流程:先将方程组写成一个增广矩阵。

然后是加减消元操作,一共进行n次。在第i次操作中,要将第i+1~n行的方程的xi的系数消为0。具体消系数的方法:假设第i行为a*x+c*y=e,要消的某一行为b*x+d*y=f,则b-=(b/a)*a,d-=(b/a)*c,f-=(b/a)*e。在第i次操作进行前,先要将i+1~n行中系数绝对值最大的方程与第i个方程交换位置,这样可以减小误差(原因玄学)而且可以避免当前行的xi系数为0。如果此时第i~n行的式子中xi系数全为0,那么方程组就有无穷多组解。

加减消元操作结束后,会得到一个上三角阶梯型矩阵。

接着是代入消元,可以发现,下面的方程比上面的方程更容易解,于是从n~1依次解元,并利用下面方程已经解得的值,消去当前方程中一些元的系数。

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=100+5;
const double eps=1e-6;	//误差范围 
int n;
double a[maxn][maxn];
inline void gauss()
{
	for(int i=1;i<=n;i++)  //加减消元 
	{
		int mx=i; for(int j=i+1;j<=n;j++) if(fabs(a[j][i])>fabs(a[mx][i])) mx=j;
		if(fabs(a[mx][i])<=eps) {printf("No Solution"); return;}
		if(mx!=i) for(int j=i;j<=n+1;j++) swap(a[i][j],a[mx][j]);
		for(int j=i+1;j<=n;j++)
			for(int k=n+1;k>=i;k--) //逆序循环,确保a[j][i]/a[i][i]是正确的
				a[j][k]-=a[j][i]/a[i][i]*a[i][k];
	}
	for(int i=n;i>=1;i--)  //代入消元
	{
		for(int j=i+1;j<=n;j++)  a[i][n+1]-=a[i][j]*a[j][n+1];	 
		a[i][n+1]/=a[i][i];     //不用修改其它系数,因为不影响答案和后续操作
	}
	for(int i=1;i<=n;i++) printf("%.2lf\n",a[i][n+1]); 
}	 
				
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)for(int j=1;j<=n+1;j++) scanf("%lf",&a[i][j]);
	gauss();
	
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
高斯消元法是一种线性代数中求解线性方程组的常用方法,它通过一系列的变换增广矩阵化为上三角矩阵,从而求出方程组的解。 下面我们来详细介绍高斯消元法的步骤: 1. 将增广矩阵写成一个矩阵形式:$$\left[\begin{array}{cccc|c}a_{11} & a_{12} & \cdots & a_{1n} & b_1 \\a_{21} & a_{22} & \cdots & a_{2n} & b_2 \\\vdots & \vdots & \ddots & \vdots & \vdots \\a_{n1} & a_{n2} & \cdots & a_{nn} & b_n \\\end{array}\right]$$ 2. 选择第一列系数最大的为第一步的主元素所在的,将该移到第一。 3. 通过消元操将第一列的其他元素变成零。具体地,对于第 $i$ ,我们将其乘以一个系数 $m_i$ 加到第一上,使得第一的第 $i$ 个元素变成零。需要注意的是,系数 $m_i$ 的取值为:$$m_i = -\frac{a_{i1}}{a_{11}}$$ 4. 将第二列系数最大的为第二步的主元素所在的,将该移到第二。 5. 通过消元操将第二列的其他元素变成零。具体地,对于第 $i$ ,我们将其乘以一个系数 $m_i$ 加到第二上,使得第二的第 $i$ 个元素变成零。需要注意的是,系数 $m_i$ 的取值为:$$m_i = -\frac{a_{i2}}{a_{22}}$$ 6. 重复上述步骤,直到将增广矩阵化为上三角矩阵。此时,方程组的解可以通过回代得到。 7. 回代过程:从最后一开始,依次求解每个未知量。具体地,对于第 $i$ 个未知量,我们先将第 $i$ 的解代入第 $i$ 个方程中,然后依次代入已知的第 $i+1$ 到第 $n$ 个未知量的解,得到第 $i$ 个未知量的解。 下面是高斯消元法的代码实现: ```c++ const double eps = 1e-8; int gauss(vector<vector<double>>& a, vector<double>& b) { int n = a.size(); int m = a[0].size() - 1; vector<int> p(n); for (int i = 0; i < n; i++) { p[i] = i; } for (int k = 0; k < m; k++) { int pivot = k; for (int i = k; i < n; i++) { if (abs(a[i][k]) > abs(a[pivot][k])) { pivot = i; } } swap(a[pivot], a[k]); swap(b[pivot], b[k]); if (abs(a[k][k]) < eps) { return -1; } for (int i = k + 1; i < n; i++) { double f = a[i][k] / a[k][k]; b[i] -= f * b[k]; for (int j = k; j < m; j++) { a[i][j] -= f * a[k][j]; } } } vector<double> x(m); for (int k = m - 1; k >= 0; k--) { x[k] = b[k]; for (int i = k + 1; i < m; i++) { x[k] -= a[k][i] * x[i]; } x[k] /= a[k][k]; } return 0; } ``` 其中,输入参数为一个 $n \times (m+1)$ 的增广矩阵 $A$ 和一个长度为 $n$ 的向量 $b$,输出为 $0$ 或者 $-1$,表示方程组有唯一解或者无解,解存储在长度为 $m$ 的向量 $x$ 中。 需要注意的是,为了防止精度误差,我们在进消元操时,如果某个数的绝对值小于一个极小值 $\epsilon$,则将其视为零。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值