(笔记)高斯-约旦消元法初步

高斯-约旦消元法

应用需求

高斯消元法应用于一系列求解多元一次(多元线性)方程中,运用了类似于可以手搓的二元一次方程的思想。

基本操作

将待求解的方程组视为\(n\)\(n+1\)列的矩阵,表示有\(n\)条方程,共有\(n\)个未知数,其中第\(n+1\)列表示方程常数位。

具体地:

\[\begin{cases} {a_{1,1}x_1+a_{1,2}x_1+...+a_{1,n}x_n=a_{1,n+1}}\\ {a_{2,1}x_1+a_{2,2}x_1+...+a_{2,n}x_n=a_{2,n+1}}\\ ...\\ {a_{n,1}x_1+a_{n,2}x_1+...+a_{n,n}x_n=a_{n,n+1}} \end{cases} \]

表示为矩阵:

\[\begin{bmatrix} a_{1,1} & a_{1,2} &...&a_{1,n}&|&a_{1,n+1}\\ a_{2,2} & a_{2,2} &...&a_{2,n}&|&a_{2,n+1}\\ ...\\ a_{n,1} & a_{n,2} &...&a_{n,n}&|&a_{n,n+1} \end{bmatrix} \]

高斯消元的过程大概有以下三个步骤:

  1. 交换某两行的位置。
  2. 用一个非\(0\)的常数乘上某个方程。
  3. 把某一行乘\(k\)然后加到另一方程上。

过程如下:

  1. 先从第一列开始,选择一个非\(0\)的系数所在的行,将其与第\(1\)行交换,令选择的系数为\(a_{i,j}\)

  2. 把选择的系数转换为\(1\),对于\(\forall 1\leq k\leq n+1,a_{i,k}\leftarrow \frac{a_{i,k}}{a_{i,j}}\),即将一行系数与常数同时除以\(a_{i,j}\)

  3. 利用选择的行将其他行同位置消除至\(0\)。(同一位置指\(\forall a_{x,j},x\in [1,n],x\neq i\)

代码实现

P3389 【模板】高斯消元法

//Gauss-Jordan Elimination
#include<bits/stdc++.h>
using namespace std;
const int N=105;
double eps=1e-7;
int n;
double a[N][N];
signed 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 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 0;
		}
		double rec=a[mx][i];
		for(int j=1;j<=n+1;j++){
			swap(a[mx][j],a[i][j]);
			a[i][j]/=rec;
		}
		for(int k=1;k<=n;k++){
			if(k==i)continue;
			rec=a[k][i]/a[i][i];
			for(int j=1;j<=n+1;j++)
				a[k][j]-=rec*a[i][j];
		}
	}
	for(int i=1;i<=n;i++)
		printf("%.2lf\n",a[i][n+1]);
	return 0;
}

简单的应用

  1. P4035 [JSOI2008] 球形空间产生器,自己构造方程组并求解,数学题。
  2. SP2883 WIDGET - Widget Factory,同余方程,求出模意义下的恒等解后枚举求解即可。
  3. P2447 [SDOI2010] 外星千足虫,同余方程,只有\(0\)\(1\),用bitset优化即可。

此外,高斯消元法还有概率DP求解,线性基等结合应用,读者可自行了解,本博客不进行详细介绍。

posted @ 2025-04-24 14:53  TBSF_0207  阅读(33)  评论(0)    收藏  举报