矩阵以及运用

首先来认识什么是矩阵

定义:

在数学中,矩阵是一个按照长方阵列排列的复数或实数集合
这是一个很简单的定义。

矩阵的运算

矩阵加减法

对于两个相同大小的矩阵,直接把相同位置的元素相加即可,如下图:
在这里插入图片描述
(这个好像并没有什么用)

重点来了

矩阵乘法

对于两个矩阵,当且仅当其中一个矩阵的行与另一个矩阵的列时,两个矩阵相乘才有意义。
A A A P × M P×M P×M的矩阵, B B B M × Q M×Q M×Q的矩阵,我们用一个矩阵 C C C来存储矩阵 A A A与矩阵 B B B的乘积。
定义在矩阵乘法中,结果 C C C矩阵的第 i i i行第 j j j列的数,就是由矩阵 A A A i i i M M M个数与矩阵 B B B j j j M M M个数分别相乘再相加得到的
即:其中矩阵 C C C中的第 i i i行第 j j j列元素可以表示为:
在这里插入图片描述
那么答案矩阵就可以表示成
在这里插入图片描述

举几个例子
在这里插入图片描述
是不是很简单,但是就是很有用。

c++代码实现:

#include <cstdio>
#include <cstring>
const int MAXN = 1e3 + 5;
struct Matrix {
    
    
	int mar[MAXN][MAXN];
	int n, m;
	Matrix() {
    
     memset(mar, 0, sizeof(mar)); }
	void Matrix_Read() {
    
     //输入矩阵
		for(int i = 0; i < n; i++) 
			for(int j = 0; j < m; j++)
				scanf("%d", &mar[i][j]);
	}
	void Matrix_Write() {
    
     //输出矩阵
		for(int i = 0; i < n; i++) {
    
    
			for(int j = 0; j < m; j++)
				printf("%d ", mar[i][j]);
			printf("\n");
		}
	}
	friend Matrix operator * (Matrix x, Matrix y) {
    
     //重载乘号并存储结果
		Matrix res; res.n = x.n; res.m = y.m;
		int sum;
		for(int i = 0; i < x.n; i++) {
    
    
			for(int j = 0; j < y.m; j++) {
    
    
				sum = 0;
				for(int k = 0; k < x.m; k++)
					sum += x.mar[i][k] * y.mar[k][j];
				res.mar[i][j] = sum;
			}
		}
		return res;
	}
};
Matrix A, B, C;
int main() {
    
    
	scanf("%d %d", &A.n, &A.m); B.n = A.m;
	A.Matrix_Read();
	scanf("%d", &B.m);
	B.Matrix_Read();
	C = A * B;
	C.Matrix_Write();
	return 0;
}

输入:

2 3
1 2 3
3 2 1
2 
1 1
2 2
3 3

输出:

2 3
1 2 3
3 2 1
2 
1 1
2 2
3 3

重要性质:

矩阵乘法能很好地运用是因为矩阵乘法支持乘法交换律
即是:
A × ( B × C ) = ( A × B ) × C A×(B×C) =(A×B)×C A×(B×C)=(A×B)×C

运用

可以很大程度上优化动态规划时的过程。
就拿斐波拉契数列来举例:
f ( i ) = f ( i − 1 ) + f ( i − 2 ) ; ( i ≤ 3 ) f(i)=f(i-1)+f(i-2);(i≤3) f(i)=f(i1)+f(i2);(i3)
很容易就想到一项一项地递推,时间复杂度为 O ( n ) O(n) O(n)
但如果 n n n达到 1 e 18 1e18 1e18甚至更大的时候,可能跑一个上午都跑不出来。
这时候就可以使用矩阵加速。
我们定义一个矩阵 [ f ( n − 2 ) , f ( n − 1 ) ] [f(n-2),f(n-1)] [f(n2),f(n1)],我们希望得到 f ( n ) f(n) f(n),即需要 [ f ( n − 1 ) , f ( n ) ] [f(n-1),f(n)] [f(n1),f(n)],需要另一个矩阵来乘上 [ f ( n − 2 ) , f ( n − 1 ) ] [f(n-2),f(n-1)] [f(n2),f(n1)]
因为 f ( n ) = f ( n − 1 ) + f ( n − 2 ) f(n)=f(n-1)+f(n-2) f(n)=f(n1)+f(n2)矩阵第一列应该是:
在这里插入图片描述

同理,矩阵第二列为:
在这里插入图片描述
所以
在这里插入图片描述
对于任意一个 n ( n ≥ 3 ) n(n≥3) n(n3)有,第 n n n项为

其中矩阵 [ 1 , 1 ] [1, 1] [1,1]表示 [ f ( 1 ) , f ( 2 ) ] [f(1), f(2)] [f(1),f(2)]

C++实现

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
#define ll long long
ll N, MOD;
struct Matrix {
    
    
	ll mar[5][5];
	ll n, m;
	Matrix() {
    
     memset(mar, 0, sizeof(mar)); }
	void Matrix_Read() {
    
    
		for(ll i = 0; i < n; i++) 
			for(ll j = 0; j < m; j++)
				scanf("%lld", &mar[i][j]);
	}
	void Matrix_Write() {
    
    
		for(ll i = 0; i < n; i++) {
    
    
			for(ll j = 0; j < m; j++)
				printf("%lld ", mar[i][j]);
			printf("\n");
		}
	}
	friend Matrix operator * (Matrix x, Matrix y) {
    
    
		Matrix res; res.n = x.n; res.m = y.m;
		ll sum;
		for(ll i = 0; i < x.n; i++) {
    
    
			for(ll j = 0; j < y.m; j++) {
    
    
				sum = 0;
				for(ll k = 0; k < x.m; k++)
					sum = (sum + x.mar[i][k] * y.mar[k][j]) % MOD;
				res.mar[i][j] = sum;
			}
		}
		return res;
	}
};
Matrix model, Fib;
void Init();
void Run();
Matrix Power(ll);
int main() {
    
    
	scanf("%lld %lld", &N, &MOD);
	Init();
	Run();
	return 0;
}
void Init() {
    
    
	Fib.mar[0][0] = 1;
	Fib.mar[0][1] = 1;
	model.mar[0][1] = 1;
	model.mar[1][0] = 1;
	model.mar[1][1] = 1;
	Fib.n = 1;
	Fib.m = model.n = model.m = 2;
}
void Run() {
    
    
	N -= 2;
	while(N) {
    
    
		if(N & 1)
			Fib = Fib * model;
		model = model * model;
		N >>= 1;
	}
	printf("%lld", Fib.mar[0][1] % MOD);
}

输入 n , m n, m n,m
输出斐波拉契第 n n n项对 m m m取模后的值

猜你喜欢

转载自blog.csdn.net/Face_the_Blast/article/details/108938464