高斯消元

盘活一下线性代数。我也不知道为什么看着格路计数然后看到LGV引理然后就来补线性代数了。

高斯消元可以拿来干什么?解方程组。线性方程组。

怎么解?我们现在有一个线性方程组长这样:

\[\left\{ \begin{aligned} a_{1,1}x_1+a_{1,2}x_2+a_{1,3}x_3+&\cdots+a_{1,n}x_n=b_1\\ a_{2,1}x_1+a_{2,2}x_2+a_{2,3}x_3+&\cdots+a_{2,n}x_n=b_2\\ a_{3,1}x_1+a_{3,2}x_2+a_{3,3}x_3+&\cdots+a_{3,n}x_n=b_3\\ &\vdots\\ a_{n,1}x_1+a_{n,2}x_2+a_{n,3}x_3+&\cdots+a_{n,n}x_n=b_n\\ \end{aligned} \right. \]

这显然是个 \(n\) 阶线性方程组。然后我们有这么一个增广矩阵:

\[\begin{pmatrix} a_{1,1} & a_{1,2} & a_{1,3} & \cdots & a_{1,n} & b_1\\ a_{2,1} & a_{2,2} & a_{2,3} & \cdots & a_{2,n} & b_2\\ a_{3,1} & a_{3,2} & a_{3,3} & \cdots & a_{3,n} & b_3\\ &&\vdots&&&\\ a_{n,1} & a_{n,2} & a_{n,3} & \cdots & a_{n,n} & b_n\\ \end{pmatrix} \]

也就是说我们把未知数的每个系数和常数组成了一个矩阵。所以说我们只需要对这个矩阵进行初等行变换,消成行最简形,然后就可以求解一个变量,进而求出所有的变量。具体说一下过程:

首先,我们把这么一个矩阵消成下三角矩阵(就是主对角线以下都是 \(0\) 的矩阵),然后最后一行就只有一个系数和一个常数,可以直接得出变量。然后从下往上一层层回带,就能得到所有的解。

还有一个叫高斯·约旦消元,这个是直接把矩阵消成对角矩阵,更常用。

然后是关于判无解的情况。如果一个位置消元之后 \(a_{i,i}=0\) ,那么如果 \(b_i\neq 0\) ,无解。如果 \(b_i=0\) ,则有无数组解。

bool gauss(){
    for(int i=1;i<=n;i++){
        int maxx=i;
        for(int j=i+1;j<=n;j++){
            if(fabs(a[j][i])>fabs(a[maxx][i]))maxx=j;//找到最大的一个
        }
        for(int j=1;j<=n+1;j++)swap(a[i][j],a[maxx][j]);//把最大的一行交换过来
		if(fabs(a[i][i])<=eps)return false;//无解
        for(int j=1;j<=n;j++){
            if(i==j)continue;
            double rate=a[j][i]/a[i][i];
            for(int k=i+1;k<=n+1;k++)a[j][k]-=a[i][k]*rate;//消元
        }
    }
    for(int i=1;i<=n;i++)ans[i]=a[i][n+1]/a[i][i];//求解答案
	return true;
}

然后是两个常见应用。

  1. 矩阵求逆。

我们现在要求一个 \(n\) 阶矩阵的逆。我们构造一个 \(n\times 2n\) 的矩阵,左边是这个 \(n\) 阶矩阵,右边是一个 \(n\) 阶单位矩阵。然后我们使用高斯消元,把左边消成单位矩阵,此时右边就是这个矩阵的逆。如果左边不是单位矩阵,则不可逆。

bool gauss(){
    for(int i=1;i<=n;i++){
        int maxx=i;
        for(int j=i+1;j<=n;j++){
            if(a[j][i]>a[maxx][i])maxx=j;
        }
        for(int j=1;j<=(n<<1);j++)swap(a[i][j],a[maxx][j]);
		if(a[i][i]==0)return false;//不可逆
		int inv=qpow(a[i][i],mod-2);
        for(int j=1;j<=n;j++){
            if(i==j)continue;
            int rate=1ll*a[j][i]*inv%mod;
            for(int k=i+1;k<=(n<<1);k++)a[j][k]=(a[j][k]-1ll*a[i][k]*rate%mod+mod)%mod;//板子
        }
		for(int j=1;j<=(n<<1);j++)a[i][j]=1ll*a[i][j]*inv%mod;//直接在这里乘上逆元 就不用最后再乘了
    }
	return true;
}
  1. 行列式求值。

不再普及行列式是什么东西。一个行列式的理解是所有列向量夹的几何体的有向体积。它有几个性质:

  1. 矩阵转置,行列式不变。
  2. 矩阵行/列交换,行列式取反。
  3. 矩阵行/列相加减,行列式不变。
  4. 矩阵一行/列所有元素同乘 \(k\) ,行列式乘 \(k\)

然后我们可以把行列式消成对角的,此时行列式的值就是对角线所有元素乘积。然后我们在消元过程中记录消元对行列式的值的影响,最后乘上即可。

int gauss(int n){
    int ans=1,w=1;
	for(int i=1;i<=n;i++){
		for(int j=i+1;j<=n;j++){
			while(a[i][i]){
				int rate=a[j][i]/a[i][i];
				for(int k=i;k<=n;k++){
					a[j][k]=(a[j][k]-1ll*rate*a[i][k]%mod+mod)%mod;
				}
				for(int k=1;k<=n;k++)swap(a[i][k],a[j][k]);
				w=-w;
			}
			for(int k=1;k<=n;k++)swap(a[i][k],a[j][k]);
			w=-w;
		}
	}
	for(int i=1;i<=n;i++)ans=1ll*ans*a[i][i]%mod;
	ans=(1ll*ans*w%mod+mod)%mod;
	return ans;
}
  1. 异或方程组

异或方程组就是把上面的线性方程组的所有加改成异或。然后所有的常数和变量都只有 \(0\)\(1\) 。事实上直接把高斯消元的加减乘改成异或就可以了。可以一行上一个bitset优化。代码不放了,没写。

posted @ 2022-10-09 11:33  gtm1514  阅读(23)  评论(0编辑  收藏  举报