矩阵乘法(从0开始)

前言

线性代数中的矩阵乘法对写编程有帮助,比如矩阵快速幂求斐波那契数列第n项之类的,所以我们要去稍微学习一些相关的运算

一.矩阵乘法的计算

运算规则:Cij = sum(Aik * Bkj)
对于两个矩阵Aij和Bnm
当且仅当j==n时,AB有意义,且结果矩阵为Cim

根据运算规则可以写成其代码

#include<bits/stdc++.h>
using namespace std;
int A[10][10],B[10][10],C[10][10];
int main(){
    
    
	int a,b,c,d;
	cin>>a>>b>>c>>d;
	for(int i=1;i<=a;i++){
    
    
		for(int j=1;j<=b;j++){
    
    
			cin>>A[i][j];
		}
	}
	for(int i=1;i<=c;i++){
    
    
		for(int j=1;j<=d;j++){
    
    
			cin>>B[i][j];
		}
	} 
	
	if(b!=c)cout<<"boring";
	else{
    
    
		for(int i=1;i<=a;i++){
    
    
			for(int j=1;j<=d;j++){
    
    
				for(int k=1;k<=b;k++){
    
    
					C[i][j]+=A[i][k]*B[k][j];
				}
			}
		}
		for(int i=1;i<=a;i++){
    
    
			for(int j=1;j<=d;j++){
    
    
				cout<<C[i][j]<<" ";
			}
			cout<<endl;
		}
	} 
	return 0;
}

矩阵快速幂

求Am
矩阵乘法满足矩阵快速幂求Am

类似的用非递归形式写快速幂即可,只不过原来的数变成了矩阵,普通的数相乘变成了矩阵乘法

#include<stdio.h>
#include<iostream>
using namespace std;
const int N=105;
const int p=1e9+7;

long long a[N][N],b[N][N];
long long ans[N][N],n;

void build_ans() {
    
    
	for(int i=1; i<=n; i++)ans[i][i]=1;
}
void build_a(){
    
    
	for(int i=1; i<=n; i++) {
    
    
		for(int j=1; j<=n; j++) {
    
    
			cin>>a[i][j];
		}
	}
}
void chen_ans() {
    
    
	for(int i=1; i<=n; i++) {
    
    
		for(int j=1; j<=n; j++)b[i][j]=ans[i][j];
	}//拷贝一个ans给b 
	
	for(int i=1; i<=n; i++) {
    
    
		for(int j=1; j<=n; j++) {
    
    
			ans[i][j]=0;
			for(int k=1; k<=n; k++) {
    
    
				ans[i][j]=(ans[i][j]+a[i][k]*b[k][j])%p;
			}
		}
	}
}
void chen_a() {
    
    
	for(int i=1; i<=n; i++) {
    
    
		for(int j=1; j<=n; j++)b[i][j]=a[i][j];
	}//拷贝一个a给b 
	
	for(int i=1; i<=n; i++) {
    
    
		for(int j=1; j<=n; j++) {
    
    
		    a[i][j]=0; 
			for(int k=1; k<=n; k++) {
    
    
				a[i][j]=(a[i][j]+b[i][k]*b[k][j])%p; 
			}
		}
	}
}
void ksm(long long m) {
    
    
	build_ans();//建立一个单位矩阵ans(AE=EA=A) 
	build_a();
	while(m) {
    
    
		if(m%2)chen_ans();
		chen_a();
		m/=2;
	}
}
int main() {
    
    
	long long m;//求方阵A的m次方
	cin>>n>>m;
	ksm(m);
	return 0;
}

二.实际用处

1.求斐波那契数列第n项

根据矩阵乘法可构造出方阵
a[1][1]=0
a[1][2]=1
a[2][1]=1
a[2][2]=1

代码如下

#include<stdio.h>
#include<iostream>
using namespace std;
const int N=105;
const int p=1e9+7;

long long a[N][N],b[N][N];
long long ans[N][N],n;

void build_ans() {
    
    
	for(int i=1; i<=2; i++)ans[i][i]=1;
}
void build_a(){
    
    
	a[1][1]=0;
	a[1][2]=1;
	a[2][1]=1;
	a[2][2]=1; 
}
void chen_ans() {
    
    
	for(int i=1; i<=2; i++) {
    
    
		for(int j=1; j<=2; j++)b[i][j]=ans[i][j];
	}
	
	for(int i=1; i<=2; i++) {
    
    
		for(int j=1; j<=2; j++) {
    
    
			ans[i][j]=0;
			for(int k=1; k<=2; k++) {
    
    
				ans[i][j]=(ans[i][j]+a[i][k]*b[k][j])%p;
			}
		}
	}
}
void chen_a() {
    
    
	for(int i=1; i<=2; i++) {
    
    
		for(int j=1; j<=2; j++)b[i][j]=a[i][j];
	}
	
	for(int i=1; i<=2; i++) {
    
    
		for(int j=1; j<=2; j++) {
    
    
			a[i][j]=0; 
			for(int k=1; k<=2; k++) {
    
    
				a[i][j]=(a[i][j]+b[i][k]*b[k][j])%p; 
			}
		}
	}
}
void ksm(long long n) {
    
    
	build_ans();
	build_a();
	while(n) {
    
    
		if(n%2)chen_ans();
		chen_a();
		n/=2;
	}
}
int main() {
    
    
	long long m;//斐波那契数列第n项
	cin>>n;
	ksm(n);
	cout<<(ans[1][1]+ans[2][1])%p;
	return 0;
}

2. x n x_n xn=(t * x n − 1 x_{n-1} xn1+p)%mod1%mod2,求第n项

例题

扫描二维码关注公众号,回复: 13121354 查看本文章

构造A
a[1][1]=t
a[1][2]=0
a[2][1]=1
a[2][2]=1
快速幂即可~
【注意】因为long long mod炸范围了,需要使用慢速乘防爆

#include<bits/stdc++.h>
using namespace std;
long long ans[5][5],a[5][5],b[5][5];
long long mod1,mod2,t,p;

long long mul(long long x,long long y){
    
    
    long long res=0;
	while(y){
    
    
		if(y%2)res=(res+x)%mod1;
		x=(x+x)%mod1;
		y/=2;
	}
	return res;
}
void build_ans(){
    
    
	ans[1][1]=1;
	ans[2][2]=1;
}
void build_a(){
    
    
	a[1][1]=t;
	a[1][2]=0;
	a[2][1]=1;
	a[2][2]=1;
}
void chen_ans(){
    
    
	for(int i=1;i<=2;i++){
    
    
		for(int j=1;j<=2;j++)b[i][j]=ans[i][j];
	} 
	for(int i=1;i<=2;i++){
    
    
		for(int j=1;j<=2;j++){
    
    
			ans[i][j]=0;
			for(int k=1;k<=2;k++){
    
    
				ans[i][j]=(ans[i][j]+mul(b[i][k],a[k][j]))%mod1;
			}
		}
	} 
}
void chen_a(){
    
    
	for(int i=1;i<=2;i++){
    
    
		for(int j=1;j<=2;j++)b[i][j]=a[i][j];
	}
	for(int i=1;i<=2;i++){
    
    
		for(int j=1;j<=2;j++){
    
    
			a[i][j]=0;
			for(int k=1;k<=2;k++){
    
    
				a[i][j]=(a[i][j]+mul(b[i][k],b[k][j]))%mod1; 
			}
		} 
	}
}
void ksm(unsigned long long n){
    
    
	build_ans();
	build_a();
	while(n){
    
    
		if(n%2)chen_ans();
		n/=2;
		chen_a();
	}
}
int main(){
    
     
    long long n,x0;
    cin>>mod1>>t>>p>>x0>>n>>mod2;
    ksm(n);
    cout<<(mul(x0,ans[1][1])+mul(p,ans[2][1]))%mod1%mod2;
	return 0;
}


3
例题3
同理构造,详解略

#include<bits/stdc++.h>
using namespace std;

long long a[4][4],ans[4][4],b[4][4],p=1e9+7; 
void chen_ans(){
    
    
	for(int i=1;i<=3;i++){
    
    
		for(int j=1;j<=3;j++)b[i][j]=ans[i][j];
	}
	for(int i=1;i<=3;i++){
    
    
		for(int j=1;j<=3;j++){
    
    
			ans[i][j]=0;
			for(int k=1;k<=3;k++){
    
    
				ans[i][j]=(ans[i][j]+b[i][k]*a[k][j])%p;
			}
		}
	}
}
void chen_a(){
    
    
	for(int i=1;i<=3;i++){
    
    
		for(int j=1;j<=3;j++)b[i][j]=a[i][j];
	}
	for(int i=1;i<=3;i++){
    
    
		for(int j=1;j<=3;j++){
    
    
			a[i][j]=0;
			for(int k=1;k<=3;k++){
    
    
				a[i][j]=(a[i][j]+b[i][k]*b[k][j])%p;
			}
		}
	}
}
void ksm(long long n){
    
    
	a[1][1]=1;
	a[1][2]=1;
	a[1][3]=0;
	a[2][1]=0;
	a[2][2]=0;
	a[2][3]=1;
	a[3][1]=1;
	a[3][2]=0;
	a[3][3]=0;
	for(int i=1;i<=3;i++){
    
    
		for(int j=1;j<=3;j++){
    
    
			if(i==j)ans[i][j]=1;
			else ans[i][j]=0;
		}
	}
	while(n){
    
    
		if(n%2)chen_ans();
		chen_a();
		n=n/2;
	}
	cout<<ans[2][3]<<endl;
}
int main() {
    
    
	long long T,n;
	cin>>T;
	while(T--){
    
    
		cin>>n;
		ksm(n+3);
	}
	return 0;
}

例题4

同理构造,详解略

#include<bits/stdc++.h>
using namespace std;

long long a[4][4],ans[4][4],b[4][4],p; 
void chen_ans(){
    
    
	for(int i=1;i<=2;i++){
    
    
		for(int j=1;j<=2;j++)b[i][j]=ans[i][j];
	}
	for(int i=1;i<=2;i++){
    
    
		for(int j=1;j<=2;j++){
    
    
			ans[i][j]=0;
			for(int k=1;k<=2;k++){
    
    
				ans[i][j]=(ans[i][j]+b[i][k]*a[k][j])%p;
			}
		}
	}
}
void chen_a(){
    
    
	for(int i=1;i<=2;i++){
    
    
		for(int j=1;j<=2;j++)b[i][j]=a[i][j];
	}
	for(int i=1;i<=2;i++){
    
    
		for(int j=1;j<=2;j++){
    
    
			a[i][j]=0;
			for(int k=1;k<=2;k++){
    
    
				a[i][j]=(a[i][j]+b[i][k]*b[k][j])%p;
			}
		}
	}
}
void ksm(long long n){
    
    
	for(int i=1;i<=2;i++){
    
    
		for(int j=1;j<=2;j++){
    
    
			if(i==j)ans[i][j]=1;
			else ans[i][j]=0;
		}
	}
	while(n){
    
    
		if(n%2)chen_ans();
		chen_a();
		n=n/2;
	}
}
int main() {
    
    
	long long t,c,a1,a2,n;
	cin>>t>>c>>a1>>a2>>n>>p;
	t%=p;
	c%=p;
	a[1][1]=t;
	a[1][2]=1;
	a[2][1]=c;
	a[2][2]=0;
	if(n==1){
    
    
		cout<<a1%p;
		return 0;
	}
	ksm(n-1);
	cout<<(a2*ans[1][2]+a1*ans[2][2])%p;
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_43602607/article/details/109687569