Luogu P3389【模板】高斯消元法

题意

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

$1 \leq n \leq 100, \left | a_i \right| \leq {10}^4 , \left |b \right| \leq {10}^4 $

题解

因为之前贺题解的时候没有理解高斯-约当消元法的实际意义所以滚回来复习了。

绝对不是因为被期望 DP 撅了才来的。

贺一下题解区的讲解。

相对于传统的高斯消元,约旦消元法的精度更好、代码更简单,没有回带的过程。

约旦消元法大致思路如下:

1.选择一个尚未被选过的未知数作为主元,选择一个包含这个主元的方程。

2.将这个方程主元的系数化为1。

3.通过加减消元,消掉其它方程中的这个未知数。

4.重复以上步骤,直到把每一行都变成只有一项有系数。

我们用矩阵表示每一项系数以及结果。

提几个要点。

1.从第一项开始枚举主元,然后选取所有行中主元系数绝对值最大的哪个。方便确认无解——若该项绝对值最大的都是 0,意味着这个主元的系数全都是 0,有无穷解。

2.选取完最大的那个之后直接将最大的作为当前行,方便后续打印方案与卡常。

3.消元直接从主元 +1 项开始。因为我们知道前面的项已经被消没了,主元项减完肯定是 0,完全不用管了。

4.最后打印的时候记得让常数项除上主元的系数。

const ll maxn=105;
db f[maxn][maxn];
ll n;
bool check(db x){
	if(fabs(x)<=1e-8)return 1;
	return 0;
}
void solve(){
	n=R;
	for(ll i=1;i<=n;i++){
		for(ll j=1;j<=n+1;j++){
			f[i][j]=1.0*R;
		}
	}
	for(ll i=1;i<=n;i++){
		ll cur=i;
		for(ll j=i+1;j<=n;j++){
			if(fabs(f[j][i])>fabs(f[cur][i]))cur=j;
		}
		for(ll j=1;j<=n+1;j++)swap(f[i][j],f[cur][j]);
		if(check(f[i][i])){
			cout<<"No Solution"<<endl;
			return ;
		}
		for(ll j=1;j<=n;j++){
			if(j==i)continue;
			db inv=f[j][i]/f[i][i];
			for(ll k=i+1;k<=n+1;k++){
				f[j][k]-=inv*f[i][k];
			}
		}
	}
	for(ll i=1;i<=n;i++){
		printf("%.2lf\n",f[i][n+1]/f[i][i]);
	}
	return ;
}

奥义·混沌邪恶·cout+快读+printf·魔怔人

posted @ 2022-10-08 15:31  Rnfmabj  阅读(19)  评论(0编辑  收藏  举报