洛谷P3389 【模板】高斯消元 高斯-约旦消元法

本文对比了高斯消元法与高斯-约旦消元法在求解线性方程组时的不同之处,详细介绍了高斯-约旦消元法的原理与实现过程,该方法通过直接将矩阵转化为简化阶梯形,从而避免了回带操作,提高了求解效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

复习的时候又翻了翻题解,发现了这个科技,挺NB的。

普通的高斯消元的思路是把一行的某一项系数变为1,然后用这个对未操作的等式的这一项消去。

于是,进行消去后的形式变成了这样(a,b,c,d是常数,x,y,z是未知数):
∣a1xb1yc1z=d10b2yc2z=d200c3z=d3∣\begin{vmatrix}a_1x & b_1y &c_1z = d_1 \\ 0 &b_2y &c_2z = d_2 \\ 0 & 0 & c_3 z = d_3\end{vmatrix}a1x00b1yb2y0c1z=d1c2z=d2c3z=d3
所以还有回带操作,对于精度有些许影响,常数稍大,还不便记忆。

普通高消code:

// luogu-judger-enable-o2
#include<bits/stdc++.h>
using namespace std;
int n;
long double Map[105][105],ans[105];
const double eps=1e-10;
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;++i)
		for(int j=1;j<=n+1;++j)
			scanf("%Lf",&Map[i][j]);
	for(int i=1;i<=n;++i){
		int r=i;
		for(int j=i+1;j<=n;++j)
			if(fabs(Map[r][i])<fabs(Map[j][i]))r=j;//选取系数最大的作为主元,用于减小误差
		if(i!=r) swap(Map[r],Map[i]);
		if(fabs(Map[i][i])<eps){
			puts("No Solution");
			return 0;
		}//这一元最大的系数为0,无解
		double Div=Map[i][i];//把这一元系数变成1
		for(int j=i;j<=n+1;++j)Map[i][j]/=Div;
		for(int j=i+1;j<=n;++j){
			Div=Map[j][i];
			for(int k=i;k<=n+1;++k)
				Map[j][k]-=Map[i][k]*Div;
		}//相减
	}
	ans[n]=Map[n][n+1];
	for(int i=n-1;i>0;--i){
		ans[i]=Map[i][n+1];
		for(int j=i+1;j<=n;++j)
			ans[i]-=Map[i][j]*ans[j];
	}//回带
	for(int i=1;i<=n;++i)printf("%.2Lf\n",ans[i]);
	return 0;
}

而我们主角——的高斯-约旦消元法,就更加简单粗暴,直接把这个矩阵变成了(省略等号):
∣a1x00d10b2y0d200c3zd3∣\begin{vmatrix}a_1x & 0 & 0 & d_1 \\ 0 &b_2y & 0 & d_2 \\ 0 & 0 & c_3 z & d_3\end{vmatrix}a1x000b2y000c3zd1d2d3

然后输出的时候直接除以系数就好了:)

具体的操作也很简单, 唯一的区别是,我们每一次都对所有的行列式一起消去这一元。
code:

#include<bits/stdc++.h>
using namespace std;
int n;
long double a[105][105];
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]);
	}
	for(int i=1;i<=n;++i){
		int p=i;
		for(int j=i+1;j<=n;++j)
			if(fabs(a[j][i])>fabs(a[p][i]))p=j;
		swap(a[i],a[p]);
		if(fabs(a[i][i])<1e-15){
			puts("No Solution");
			return 0;
		}
		for(int j=1;j<=n;++j)//与普通高消最大的不同。
			if(j!=i){
				double tmp=a[j][i]/a[i][i];
				for(int k=i+1;k<=n+1;++k)
					a[j][k]-=a[i][k]*tmp;
			}
	}
	for(int i=1;i<=n;++i){
		printf("%.2Lf\n",a[i][n+1]/a[i][i]);
	}
	return 0;
}

另外:用long double时记得使用eps,窝有次就锅在这了,然而用double直接判0即可(

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值