个人已知的线性代数科技

本文比较杂,涉及多方面

#1 矩阵

*1 矩阵乘法

\[\left[ \begin{array}{ll} 1&0&0\\ 0&1&0\\ 0&0&1 \end{array} \right] \]

​ 通常而言,矩阵乘法是用于实现线性变换的一种工具,一般将一个对象矩阵乘上变换矩阵就可以实现线性变换或者某一阶段的线性变换。而信息学中则利用了矩阵乘法的结合律,从而实现了快速变换的过程。

例题

现在给定一个数列的线性递推式:

\(a_n+a_{n+1}=a_{n+2}\) (斐波那契数列)

\(a_0=0,a_1=1\)

solution

可以构造初始状态矩阵:

\[A= \left[ \begin{array}{ll} 1&0 \end{array} \right] \]

以及转移矩阵:

\[B=\left[ \begin{array}{ll} 1 & 1\\ 1 & 0 \end{array} \right] \]

然后设 \(K_i=A\times B^i\)

根据转移方式不难发现实际上

\[K_i=\left[ \begin{array}{ll} a_{i+1} & a_i \end{array} \right] \]

然后因为矩阵乘法具有结合律,那么可以先把 \(B^i\) 给计算出来,再来计算 \(K_i\)

至于如何快速计算 \(B^i\) ,可以模仿快速幂算法一样,时间复杂度是迭代次数乘以矩阵乘法的时间,即:

\(T(n)=O(log_2 i)\times O(2\times 2\times2)\) ~ \(O(log_2i)\)

​ 所以矩阵在处理这种线性转移的问题的时候能够成为非常合适的一类工具。

*2 广义矩阵乘法

​ 对于更多问题而言,其计算过程并不是简单的矩阵乘法,而有可能是加权取最值,按位异或、与、或等,但是只要其转移是线性的,那么依旧可以使用矩阵来进行求解,如果这个转移满足结合律,那么他甚至可以用类似的方法优化成 \(O(log_2n)\)时间级别的。

例题

给定一张带权有向图,问经过恰好 \(k\) 条边后从节点 \(u\) 到达节点 \(v\) 的最短路是多少

solution

同样可以构造初始矩阵 \(A\) 满足 \(a_{ij}\) 表示从节点 \(i\) 走到节点 \(j\) 的最短路是多少,然后转移矩阵就是类似于 \(Floyed\) 算法中的一样,而转移方式也是同 \(Floyed\) 算法一样,因为不难证明这个是具有结合律而却是线性的

#2 高斯消元

其实就是解多元线性方程组,形式如

\[\left( \begin{array}{ll} a_{11}x_1+a_{12}x_2+a_{13}x_3....=b_1\\ a_{21}x_1+a_{22}x_2+a_{23}x_3....=b_2\\ a_{31}x_1+a_{32}x_2+a_{33}x_3....=b_3\\ a_{41}x_1+a_{42}x_2+a_{43}x_3....=b_4\\ ..... \end{array} \right) \]

然后就是模拟算法吧,模拟小学生解方程一样:

代码如下

#include <bits/stdc++.h>
#define int long long
using namespace std; 
inline int read(){
	int x=0,f=1;char ch=getchar();
	while(!isdigit(ch))f^=(ch=='-'),ch=getchar();
	while(isdigit(ch))x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
	return f?x:-x;
}
double a[115][115],ans[115];
int n;
int Gauss(){
	for(int k=1;k<=n;k++){
		int notpossible=1;
		for(int i=1;i<=n-k+1;i++){
			if(a[i][k]!=0){
				swap(a[i],a[1]);
				notpossible=0;
				break;
			}
		}
		if(notpossible)return 1;
		for(int i=1;i<=n-k+1;i++){
			if(a[i][k]!=0){
				for(int j=n+1;j;j--)
					a[i][j]/=a[i][k];
			}
		}
		for(int i=2;i<=n-k+1;i++){
			if(a[i][k]!=0){
				for(int j=1;j<=n+1;j++)
					a[i][j]-=a[1][j];
			}
		}
		swap(a[1],a[n-k+1]);
	}
	for(int k=n;k;k--){
		int i=n-k+1;
		ans[k]=a[i][n+1];
		for(int j=n;j>k;j--)
			ans[k]-=a[i][j]*ans[j];
	}
	return 0;
}
signed main(){
	n=read();
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n+1;j++){
			scanf("%lf",&a[i][j]);
		}
	}
	int k=Gauss();
	if(k)printf("No Solution");
	else{
		for(int i=1;i<=n;i++){
			printf("%.2lf\n",ans[i]);
		}
	}
}

其实高斯消元在取模意义下依然可以成立,前提是逆元存在

#3 行列式

行列式是一类类似于求解生成排列加权的计数工具,目前并不常见(算法里头好像就是Matrix-Tree定理用到过,其他的就算出题了也不会做)

定义方阵 \(A\) :

\[det(A)=\left| \begin{array}{ll} a_{11}&a_{12}&...&a_{1n}\\ a_{21}&a_{22}&...&a_{2n}\\ ...&...&...&...\\ a_{n1}&a_{n2}& ... & a_{nn} \end{array} \right| \]

计算方法:

使用高斯消元将 \(A\) 变成下三角矩阵或者上三角矩阵,然后将对角线直接乘起来即可

posted @ 2024-10-25 21:48  chx#XCPC  阅读(2)  评论(0编辑  收藏  举报