首页 > 其他分享 >高斯消元

高斯消元

时间:2024-09-14 21:02:19浏览次数:1  
标签:end int eps -- bmatrix now 高斯消

高斯消元

网上的题解一个比一个难看,还一人一个码风。

如果我知道谁还要学高斯消元,我会让他先做 [SDOI2006] 线性方程组 再做 【模板】高斯消元法,因为前者需要判出无解或无穷解,而后者只需要输出 No Solution 同时代表这两种情况,前者更通用一些,而写法却差得不少,从前者往后者转就是薄纱。

首先这玩意的思路就是代入消元和加减消元,只不过元的个数来到了 \(100\),复杂度是 \(O(n^3)\) 的。注意最好别开中间变量,因为这玩意全程要用 double 运算,我每次开变量都习惯开成 int,不知道啥时候就开始错了。还有判断零,由于精度问题,我们设一个 \(eps = 10^{-7}\),只要一个 doublefabs 比 \(eps\) 小我们就认为它是 \(0\) 了。

先放完整模板,再慢慢解释。

const int N = 1e2+5;
double eps = 1e-8;
double a[N][N];
double ans[N];
int n;
void gauss()
{
	int now{1};
	for(int i{1};i<=n;i++) // main 
	{
		for(int j{now};j<=n;j++)
		if(fabs(a[j][i]) > eps) // turn to now top
		{
			swap(a[j],a[now]);
			break;
		}
		if(fabs(a[now][i]) > eps)
		{
			for(int j{n+1};j>=i;j--) a[now][j] /= a[now][i];// to 1
			for(int j{now+1};j<=n;j++)
			{
				for(int k{n+1};k>=i;k--) a[j][k] -= a[now][k] * a[j][i];//+- delete
			}
			now++;
		}
	}
	if(now<n+1)
	{
		for(int i{now};i<=n;i++)
		{
			if(fabs(a[i][n+1]) > eps) puts("-1"),exit(0); //no solution
		}
		puts("0"),exit(0); // infinity solution
	}
	ans[n] = a[n][n+1];
	for(int i{n-1};i>=1;i--)
	{
		ans[i] = a[i][n+1];
		for(int j{i+1};j<=n;j++)
			ans[i] -= a[i][j] * ans[j];
	}
}
signed main()
{
	#ifdef LOCAL
	freopen("in.in","r",stdin);
	#endif
	n = read();
	for(int i{1};i<=n;i++)
		for(int j{1};j<=n+1;j++)
		a[i][j] = 1.0 * read();
	gauss();
	for(int i{1};i<=n;i++)
	{
		printf("x%lld=%.2Lf\n",i,ans[i]); 
	}
	exit(0);
}

\(\begin{Bmatrix} 3x & + & 2y &+& z &=&10 \\5x & + & y &+& 6z &=&25 \\2x & + & 3y &+& 4z &=&20\end{Bmatrix}\)

我们发现一个 \(n\) 元的线性同余方程组有 \(n\) 个方程,每个方程有 \(n+1\) 项。我们称

\(\begin{bmatrix} 3 & 2 & 1 \\5 & 1 & 6 \\2 & 3 & 4 \end{bmatrix}\)​ 为它的系数矩阵,

\(\begin{bmatrix} 3 & 2 & 1 &10 \\5 & 1 & 6 &25 \\2 & 3 & 4 &20\end{bmatrix}\) 为它的增广矩阵。

首先你需要读入一个增广矩阵。

for(int i{1};i<=n;i++)
	for(int j{1};j<=n+1;j++)
	a[i][j] = 1.0 * read();

然后就可以开始 gauss() 了。

int now{1};

首先我们定义一个 now,表示的是当前已经手动消掉了多少行。为什么是“手动”?因为有的行那一项天生系数就是 \(0\),就不需要自己消,那么就可能会出现无解、无穷解的情况。为什么初始化为 \(1\)?因为我们要从第一行开始计算,这刚好可以是我们的初始行位置。

for(int i{1};i<=n;i++) // main 
	{
		for(int j{now};j<=n;j++)
		if(fabs(a[j][i]) > eps) // turn to now top
		{
			swap(a[j],a[now]);
			break;
		}
		if(fabs(a[now][i]) > eps)
		{
			for(int j{n+1};j>=i;j--) a[now][j] /= a[now][i];// to 1
			for(int j{now+1};j<=n;j++)
			{
				for(int k{n+1};k>=i;k--) a[j][k] -= a[now][k] * a[j][i];//+- delete
			}
			now++;
		}
	}

接下来这部分是加减消元。

我们外层枚举的 \(i\) 是主元,然后枚举 \(j\) 从 now 到 \(n\),找到一个当前元系数非 \(0\) 的式子并把它提到 now 的这一行(当然如果没找到就 continue),然后把下面所有的行的 \(i\) 元全部消掉,并给 now 递增,这样就保证了 \(1\) 到 now-1 行都是被消过的。我们下一次枚举行只需要从递增过的 now 行枚举即可了。

怎么加减消元?先把当前行的当前元的系数置为 \(1\),当前行的其他系数相应改变。接着我们就拿着这行去消下面所有的行的 \(i\) 元,因为当前行的 \(i\) 系数已经为 \(1\) 了,那么遇到哪行就相应扩那行的 \(i\) 系数倍,一项一项减就行了。注意行内是倒着枚举,因为要用到 \(i\) 元的系数,不能一上来就清零了。

if(now<n+1)
	{
		for(int i{now};i<=n;i++)
		{
			if(fabs(a[i][n+1]) > eps) puts("-1"),exit(0); //no solution
		}
		puts("0"),exit(0); // infinity solution
	}

这一部分是判断有无解的。如果你没有 continue 过,那么你的 now 经过 \(n\) 次递增肯定会变成 \(n+1\),而现在 now 如果比 \(n+1\) 小,则说明有元没有手动消,就会出现无解无穷解的情况。

解的情况:

唯一解:\(i\) 可以枚举完 \(n\) 行 \(\begin{bmatrix} 1 & 1 & 1 & 6\\0 & 1 & 2 & 8 \\0 & 0 & 1 & 3 \end{bmatrix}\)

无解:\(a[i][i] = 0,b\neq 0\) \(\begin{bmatrix}1 &1 & 1 & 6 \\0 & 1 & 2 & 3 \\ 0 & 0 & 0&3\end{bmatrix}\)

无穷多解:\(a[i][i]=0,b = 0\) \(\begin{bmatrix}1&1&1&6\\0&1&2&3\\0&0&0&0\end{bmatrix}\)。

我们既然能进到这个 if 里,说明从 now 到 \(n\) 行之内的 \(a_{i,i}\) 都是 \(0\) 了,那么我们只需要 \(\text{check}\) 一下 \(a_{i,{n+1}}\) 的大小,注意无解的优先级是比无穷解高的。

ans[n] = a[n][n+1];
	for(int i{n-1};i>=1;i--)
	{
		ans[i] = a[i][n+1];
		for(int j{i+1};j<=n;j++)
			ans[i] -= a[i][j] * ans[j];
	}

之后从下往上回带就可以了。

标签:end,int,eps,--,bmatrix,now,高斯消
From: https://www.cnblogs.com/myyy115922/p/18414668

相关文章

  • 高斯消元法
    模板题我写不明白我要用其他人的学习笔记其实也没法写,真要一步步写很复杂。无非就是依次将每个数减掉系数,最后成为一个单位矩阵。所以看注释:#include<bits/stdc++.h>usingnamespacestd;#definelllonglongconstintN=1e5+5;intn;//n表示方......
  • 高斯消元解线性方程组
    高斯消元解线性方程组输入一个包含n个方程n个未知数的线性方程组。方程组中的系数为实数。求解这个方程组。下图为一个包含m个方程n个未知数的线性方程组示例输入格式第一行包含整数n。接下来n行,每行包含n+1个实数,表示一个方程的n个系数以及等号右侧的常数......
  • 有关用MATLAB来实现高斯消去法
    题目:利用Gaussian消去法求解线性方程组Ax=b,其中:     实现流程程序代码实验结果......
  • Note - 高斯消元法(证明略)
    线性代数高斯消元法求解线性方程组高斯消元法是求解线性方程组的经典算法,还可以用于行列式计算、求矩阵的逆。部分代码From「SDOI2006」线性方程组doublea[N][N];//a[i][j]表示第i个方程中第j个元的系数,a[i][n+1]为等号右侧的常数项voidGauss(){for(inti=1;i<......
  • 详细揭秘:特殊图高斯消元
    树上高斯消元给你一颗树,某些点为终止结点,求从每个点开始随机游走走到某个终止节点的期望时间。从叶子开始将\(f(u)\)表示为\(k(u)f(\text{fa}(u))+b(u)\),带回\(f(\text{fa}(u))\)的方程中将\(f(u)\)消掉即可。DAG上高斯消元可重集/reset有一个可重集\(S\),每一......
  • 高斯消元 学习笔记
    用于求解方程组。给定\(n\)个关于\(m\)个变量的方程组,需要你判断该方程组是否无解、有无数解、有唯一解,并输出唯一的解。考虑使用消元法。我们枚举一个变量\(i\),从所有没有被操作过的方程式中选出一个,然后用它对其他没有被操作过的方程式进行消元,并将被选中的那个方程式视......
  • 高斯消元
    1.高斯消元的基础信息本质通过初等行变化,将线性方程组的增广矩阵转化为行阶梯矩阵,讲人话就是用加减消元来转化,代入消元来回带。应用用来求解线性方程组(m个一次方程,n个变量),矩阵的秩(校园后的主元数)以及求可逆方阵的逆矩阵。难度思维难度低,代码实现难度低复杂度时间:O(n^3)空间......
  • 可变阶数高斯消元算法-passcal-c shap-c语言
    高斯消元法在各种工程领域都有广泛的应用,尤其是在需要求解线性方程组的情况下。尽管高斯消元法在某些情况下可能不是最高效的算法,但它仍然是一个强大且通用的工具,对于许多工程问题来说是非常实用的。随着计算机性能的提高,高斯消元法在处理大规模问题时也变得更加可行。高斯消......
  • 高斯消元
    高斯消元高斯消元法通常用于求解如下的\(n\)元线性方程组\[\begin{cases}a_{1,1}x_1+a_{2,2}x_2+\cdots+a_{1,n}x_n=b_1\\a_{2,1}x_1+a_{2,2}x_2+\cdots+a_{2,n}x_n=b_2\\\cdots\\a_{n,1}x_1+a_{n,2}x_2+\cdots+a_{n,n}......
  • 高斯消元
    #include<iostream>#include<cassert>#include<cstdio>#include<cstring>#include<algorithm>#include<vector>#include<map>#include<cmath>#include<queue>#include<set>#include<cli......