基础线性代数

基础线性代数

矩阵变换

将向量逆时针旋转90°:左乘

0 -1
1  0    

将向量延长至两倍:左乘

2 0
0 2

矩阵乘法

#include <bits/stdc++.h>
#define Mod 1000000007
#define maxn 3
using namespace std;
long long n,L=2;
struct Matrix{
    long long M[maxn][maxn];
    void clear(){		//矩阵清零
        memset(M,0,sizeof(M));
    }
    void reset(){		//设置为单位矩阵
        clear();
        for(int i=0;i<L;++i)	M[i][i]=1;
    }
    Matrix friend operator *(const Matrix &A,const Matrix &B){
        Matrix Ans;
        Ans.clear();		//L是矩阵的大小(行数与列数)
        for(int i=0;i<L;++i){
            for(int j=0;j<L;++j){
                for(int k=0;k<L;++k){
                    Ans.M[i][j]=(Ans.M[i][j]+A.M[i][k]*B.M[k][j])%Mod;
                }
            }
        }
        return Ans;
    }
}A,B,C;
int main(){
	for(int i=0;i<L;i++){
    	for(int j=0;j<L;j++){
    		cin>>A.M[i][j];
		}
	}
	for(int i=0;i<L;i++){
    	for(int j=0;j<L;j++){
    		cin>>B.M[i][j];
		}
	}
	//可以这么计算矩阵乘法,其中A、B、C均为Matrix类型
    C=A*B;
    for(int i=0;i<L;i++){
    	for(int j=0;j<L;j++){
    		cout<<C.M[i][j]<<" ";
		}
		cout<<endl;
	}
    return 0;
}

矩阵快速幂

例题:洛谷P1962 斐波那契数列

P1962 斐波那契数列 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

求出Fn mod 109+7的值

n<=2,Fn=1

n>2,Fn=Fn-2+Fn-1

我们可以想到,通过矩阵加速递推

F(n-1)	->	F(n)
F(n-2)		F(n-1)

所以我们可以推出

F(n)	=  1 1	* 	F(n-1)
F(n-1)	   1 0	    F(n-2)

所以

F(n)	=  1 1	^(n-2) * 	1
F(n-1)	   1 0	    		1

用矩阵快速幂求出

1 1	^(n-2) 
1 0	

然后求出Fn=[0][0]+[0][1]

#include <bits/stdc++.h>
#define Mod 1000000007
#define maxn 3
using namespace std;
long long n,L=2;
struct Matrix{
    long long M[maxn][maxn];
    void clear(){		//矩阵清零
        memset(M,0,sizeof(M));
    }
    void reset(){		//设置为单位矩阵
        clear();
        for(int i=0;i<L;++i)	M[i][i]=1;
    }
    Matrix friend operator *(const Matrix &A,const Matrix &B){
        Matrix Ans;
        Ans.clear();		//L是矩阵的大小(行数与列数)
        for(int i=0;i<L;++i){
            for(int j=0;j<L;++j){
                for(int k=0;k<L;++k){
                    Ans.M[i][j]=(Ans.M[i][j]+A.M[i][k]*B.M[k][j])%Mod;
                }
            }
        }
        return Ans;
    }
}A;
Matrix expow(Matrix T,long long P){	//矩阵快速幂
    Matrix Ans;
    Ans.reset();
    while(P){
        if(P&1)		Ans=Ans*T;
        T=T*T,P>>=1;
    }
    return Ans;
}
int main(){
    cin>>n;
    if(n<=2){
        cout<<1;
        return 0;
    }
    A.M[0][0]=1;
    A.M[0][1]=1;		//构造递推矩阵
    A.M[1][0]=1;		
    A.M[1][1]=0;
    A=expow(A,n-2);			//矩阵快速幂
    cout<<(A.M[0][0]+A.M[0][1])%Mod;		//计算结果
    return 0;
}

另一类似题 P1939 【模板】矩阵加速(数列)

P1939 【模板】矩阵加速(数列) - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

易得,递推矩阵为

0 1 0
0 0 1
1 0 1

高斯消元

例题 P2455 线性方程组

[P2455 SDOI2006]线性方程组 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

n为未知数个数,接下来n行 输入每一行的系数和b值

如果有唯一解,则输出解(小数点后保留两位小数)。如果方程组无解输出 -1; 如果有无穷多实数解,输出 0;

\[a_{11}x_1+a_{12}x_2+...+a_{1n}x_n=b_1\\ a_{21}x_1+a_{22}x_2+...+a_{2n}x_n=b_2\\ ...\\ a_{n1}x_1+a_{n2}x_2+...+a_{nn}x_n=b_n \]

#include <bits/stdc++.h>
using namespace std;
#define maxn 110
#define eps 1e-6
int n,curi=0;				//curi表示枚举哪一行
double a[maxn][maxn];
int main(){
	cin>>n;
	for(int i=0;i<n;i++)
		for(int j=0;j<n+1;j++)
			cin>>a[i][j];
	for(int j=0;j<n;j++){
		int t;
		for(t=curi;t<n;t++)
			if(fabs(a[t][j])>eps)	break;			//找到一列非零元素
		if(t==n)	continue;						//这一列没有找到非零元素
		for(int i=j;i<=n;i++)
			swap(a[t][i],a[curi][i]);				//把非0元素所在行交换到当前行
		for(int i=n;i>=j;i--)
			a[curi][i] /= a[curi][j];				//当前行同除,令主元系数划一
		for(int i=0;i<n;i++)						//对其他行消元
			if(i!=curi)
				for(int k=n;k>=j;k--)
					a[i][k]-=a[curi][k]*a[i][j];
		curi++;			
	}	
	if(curi<n){										//判断0!=0
		for(int i=curi;i<n;i++)
			if(fabs(a[i][n])>eps){					//发现0!=0,无解
				puts("-1");
				return 0;
			}
		puts("0");									//发现0=0,无穷多解
	}else
		for(int i=0;i<n;i++)
			printf("x%d=%.2lf\n",i+1,a[i][n]);
	return 0;	
}

行列式求值

例题 P7112 行列式求值

P7112 【模板】行列式求值 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

输入n和p(模数),接下来输入这个行列式

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
const int maxn=602;
int a[maxn][maxn];
int n,p,i,j;
int cal(int a[][maxn],int n,int p)
{
	int i,j,k,r=1,fh=0,l;
	for (i=1;i<=n;i++)
	{
		k=i;
		for(j=i;j<=n;j++){
			if(a[j][i]){
				k=j;
				break;
			}
		}
		if(a[k][i]==0) return 0;
		for(++j;j<=n;j++){
			if(a[j][i]&&a[j][i]<a[k][i]) k=j;
		} 
		if(i!=k){
			swap(a[k],a[i]);
			fh^=1;
		}
		for(j=i+1;j<=n;j++)
		{
			if(a[j][i]>a[i][i]){
				swap(a[j],a[i]);
				fh^=1;
			}
			while(a[j][i])
			{
				l=a[i][i]/a[j][i];
				for(k=i;k<=n;k++) 
					a[i][k]=(a[i][k]+(ll)(p-l)*a[j][k])%p;
				swap(a[j],a[i]);
				fh^=1;
			}
		}
		r=(ll)r*a[i][i]%p;
	}
	if(fh) return (p-r)%p;
	return r;
}
int main()
{
	IOS;
	cin>>n>>p;
	for(i=1;i<=n;i++){
		for(j=1;j<=n;j++){
			cin>>a[i][j];
			a[i][j]%=p;
		}
	} 
	cout<<cal(a,n,p);
}
posted @ 2022-09-22 21:31  钰见梵星  阅读(56)  评论(0编辑  收藏  举报