线性代数笔记1

一.行列式

1.行列式定义

\( \left | \begin{matrix} a_{11} &a_{12} &... &a_{1n} \\ a_{21} &a_{22} &... &a_{2n} \\ ... &... &... &...\\ a_{n1} &a_{n2} &... &a_{nn} \end{matrix} \right | \)
将此称为\(n\)阶行列式
\(p\)数组为\(n\)的全排列,\(t\)\(p\)数组的逆序对数
则此行列式的值为\(\sum (-1)^ta_{1p_{1}}a_{1p_{2}}...a_{1p_{n}}\)

2.重要的结论及性质

1.上三角行列式的值为对角线的乘积

\[\left | \begin{matrix} a_{11} &a_{12} &... &a_{1n} \\ 0 &a_{22} &... &a_{2n} \\ ... &... &... &...\\ 0 &0 &... &a_{nn} \end{matrix} \right | = a_{11}a_{22}...a_{nn} \]

2.下三角行列式的值为对角线的乘积

\[\left | \begin{matrix} a_{11} &0 &... &0 \\ a_{21} &a_{22} &... &0 \\ ... &... &... &...\\ a_{n1} &a_{n2} &... &a_{nn} \end{matrix} \right | = a_{11}a_{22}...a_{nn} \]

3.对角行列式的值为对角线的乘积

\[\left | \begin{matrix} a_{11} &0 &... &0 \\ 0 &a_{22} &... &0 \\ ... &... &... &...\\ 0 &0 &... &a_{nn} \end{matrix} \right | = a_{11}a_{22}...a_{nn} \]

4.若互换行列式的任意两行(列),则行列式变号

\[\left | \begin{matrix} a_{11} &a_{12} &... &a_{1n} \\ a_{21} &a_{22} &... &a_{2n} \\ ... &... &... &...\\ a_{n1} &a_{n2} &... &a_{nn} \end{matrix} \right | = -\left | \begin{matrix} a_{21} &a_{22} &... &a_{2n} \\ a_{11} &a_{12} &... &a_{1n} \\ ... &... &... &...\\ a_{n1} &a_{n2} &... &a_{nn} \end{matrix} \right | \]

5.若行列式的一行乘上一个数k,则行列式的值也乘上一个数k

\[\left | \begin{matrix} a_{11} &a_{12} &... &a_{1n} \\ a_{21}*k &a_{22}*k &... &a_{2n}*k \\ ... &... &... &...\\ a_{n1} &a_{n2} &... &a_{nn} \end{matrix} \right | = k*\left | \begin{matrix} a_{11} &a_{12} &... &a_{1n} \\ a_{21} &a_{22} &... &a_{2n} \\ ... &... &... &...\\ a_{n1} &a_{n2} &... &a_{nn} \end{matrix} \right | \]

6.若行列式的一行同时加(减)一个数,该行列式可拆成两个行列式之和

\[\left | \begin{matrix} a_{11} &a_{12} &... &a_{1n} \\ a_{21}+b_{21} &a_{22}+b_{22} &... &a_{2n}+b_{2n} \\ ... &... &... &...\\ a_{n1} &a_{n2} &... &a_{nn} \end{matrix} \right | = \left | \begin{matrix} a_{11} &a_{12} &... &a_{1n} \\ a_{21} &a_{22} &... &a_{2n} \\ ... &... &... &...\\ a_{n1} &a_{n2} &... &a_{nn} \end{matrix} \right | + \left | \begin{matrix} a_{11} &a_{12} &... &a_{1n} \\ b_{21} &b_{22} &... &b_{2n} \\ ... &... &... &...\\ a_{n1} &a_{n2} &... &a_{nn} \end{matrix} \right | \]

3.在\(O(n^3+n^2logn)\)的时间复杂度内求行列式的值

行列式求值模版
本题坑点:p不为素数
此题可以通过高斯消元将原行列式变换成三角行列式(因时间复杂度不足(可能是我太菜了),无法变换成对角行列式),再求出对角乘积即可,但因为模数为素数,所以需要辗转相减,所以时间复杂度为\(O(n^3+n^2logn)\),代码如下:

#include <cstdio>
#include <algorithm>
#define int long long
using namespace std;
int jz[605][605];
int n;
int p;
signed main(){
	scanf("%lld%lld",&n,&p);
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			scanf("%lld",&jz[i][j]);
			jz[i][j]%=p;
		}
	}
	int w=1;
	for(int i=1;i<=n;i++){
		for(int j=i+1;j<=n;j++){
			if(i==j){
				continue;
			}
			/*int bs=jz[j][i]/jz[i][i];
			for(int k=1;k<=n;k++){
				jz[j][k]=(jz[j][k]-jz[i][k]*bs%p+p)%p;
			}*/
			/*if(jz[i][i]>jz[j][i]){
				for(int k=1;k<=n;k++){
					swap(jz[i][k],jz[j][k]);
				}
				w=-w;
			}*/
			while(jz[i][i]!=0){
				int bs=jz[j][i]/jz[i][i];
				for(int k=1;k<=n;k++){
					jz[j][k]=(jz[j][k]-bs*jz[i][k]%p+p)%p;
				}
				for(int k=1;k<=n;k++){
					swap(jz[j][k],jz[i][k]);
				}
				w=-w;
			}
			for(int k=1;k<=n;k++){
				swap(jz[j][k],jz[i][k]);
			}
			w=-w;
		}
	}
	/*for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			printf("%d ",jz[i][j]); 
		}
		printf("\n"); 
	}*/
	int ans=1;
	for(int i=1;i<=n;i++){
		ans*=jz[i][i];
		ans%=p;
	}
	ans=(ans*w+p)%p;
	printf("%lld",ans);
	return 0;
}

4.matrix-tree定理

对于无向图的基尔霍夫矩阵定义:\(T_{i,j}=\begin{cases}\sum_{k=1}^{n}w_{i,k} &(i==j) \\ -w_{i,j} &(i\ne j)\end{cases}\)
该矩阵有如下性质:
1.该矩阵的任意一行或任意一列的和是相等的(显然)
推论:该矩阵对应的行列式的值为0
2.若将该矩阵的同编号的一行和一列删除,则该行列式的绝对值为生成树的个数。
对于有向图的基尔霍夫矩阵(外向树)定义:\(T_{i,j}=\begin{cases}\sum_{k=1}^{n}w_{k,i} &(i==j) \\ -w_{i,j} &(i\ne j)\end{cases}\)
此矩阵有一特殊性质:若将该矩阵的同编号的一行和一列删除,则该行列式的绝对值为以此编号为根的生成树(外向树)的个数。
内向树与外向树的区别:外向树ij时记录的是入度,而内向树ij时记录的是出度。

对于三种情况:

1.无向图生成树计数

使用无向图的基尔霍夫矩阵,删除任意一组同编号的一行和一列即可

2.有向图外向树计数

使用有向图的基尔霍夫矩阵(外向树),删除根节点编号的一行和一列即可

3.有向图内向树计数

使用有向图的基尔霍夫矩阵(内向树),删除根节点编号的一行和一列即可

加权扩展:

若图有边权,则根据乘法原理,可以将边权看作重编,所以注意度数数组
Matrix-tree模版
代码:

#include <cstdio>
#define int long long
#define mod 1000000007
using namespace std;
int n,m,t;
struct hls{
	int k1;
	int d[305][305];
	/*friend hls operator - (hls a,hls b){
		hls ans;
		ans.k1=a.k1;
		for(int i=1;i<=ans.k1;i++){
			for(int j=1;j<=ans.k1;j++){
				ans.d[i][j]=a.d[i][j]-b.d[i][j];
			}
		}
		return ans;
	}*/
	int qz(){
		int w=1;
		for(int i=1;i<=k1;i++){
			for(int j=i+1;j<=k1;j++){
				if(d[j][i]>d[i][i]){
					for(int k=1;k<=k1;k++){
						int tmp;
						tmp=d[j][k];
						d[j][k]=d[i][k];
						d[i][k]=tmp;
					}
					w=-w;
				}
				int k2;
				while(d[j][i]!=0){
					k2=d[i][i]/d[j][i];
					for(int k=1;k<=k1;k++){
						d[i][k]=(d[i][k]-k2*d[j][k]%mod+mod)%mod;
					}
					for(int k=1;k<=k1;k++){
						int tmp;
						tmp=d[j][k];
						d[j][k]=d[i][k];
						d[i][k]=tmp;
					}
					w=-w;
				}
			}
		}
		int ans=1;
		for(int i=1;i<=k1;i++){
			ans*=d[i][i];
			ans%=mod;
		}
		ans=(ans*w+mod)%mod;
		return ans;
	}
}jz;
signed main(){
	scanf("%lld%lld%lld",&n,&m,&t);
	if(t==0){
		for(int i=1;i<=m;i++){
			int u,v,w;
			scanf("%lld%lld%lld",&u,&v,&w);
			if(u!=n){
				jz.d[u][u]=(jz.d[u][u]+w)%mod;
				if(v!=n){
					jz.d[u][v]=(jz.d[u][v]-w+mod)%mod;
					jz.d[v][u]=(jz.d[v][u]-w+mod)%mod;
				}
			}
			if(v!=n){
				jz.d[v][v]=(jz.d[v][v]+w)%mod;
			}
		}
		jz.k1=n-1;
		int ans=jz.qz();
		printf("%lld\n",ans);
	}
	else{
		for(int i=1;i<=m;i++){
			int u,v,w;
			scanf("%lld%lld%lld",&u,&v,&w);
			if(u!=1){
				//jz.d[u][u]=(jz.d[u][u]+w)%mod;
				if(v!=1){
					jz.d[u-1][v-1]=(jz.d[u-1][v-1]-w+mod)%mod;
					//jz.d[v][u]=(jz.d[v][u]-w+mod)%mod;
				}
			}
			if(v!=1){
				jz.d[v-1][v-1]=(jz.d[v-1][v-1]+w)%mod;
			}
		}
		jz.k1=n-1;
		int ans=jz.qz();
		printf("%lld\n",ans);
	}
	return 0;
}
posted on 2024-09-15 11:53  jisuheng123  阅读(63)  评论(2编辑  收藏  举报