矩阵乘法相关内容

矩阵乘法

内容简介

矩阵相乘最重要的方法是一般矩阵乘积。它只有在第一个矩阵的列数(column)和第二个矩阵的行数(row)相同时才有意义 。一般单指矩阵乘积时,指的便是一般矩阵乘积。一个m×n的矩阵就是m×n个数排成m行n列的一个数阵。由于它把许多数据紧凑地集中到了一起,所以有时候可以简便地表示一些复杂的模型

定义

A A A n ∗ m n*m nm 的矩阵, B B B m ∗ q m*q mq 的矩阵,那么称 的矩阵 C = n ∗ q C=n*q C=nq
,并且必须满足 矩 阵 A 矩阵A A的列和 矩 阵 B 的 行 数 矩阵B的行数 B一样才可以做矩阵乘法
假设此时 A = 3 ∗ 3 B = 3 ∗ 2 C = 3 ∗ 2 \\A=3*3 \\ B=3*2 \\ C=3*2 A=33B=32C=32
A = { a 1 , 1 a 1 , 2 a 1 , 3 a 2 , 1 a 2 , 2 a 2 , 3 a 3 , 1 a 3 , 2 a 3 , 3 } A=\left\{ \begin{matrix} a_{1,1}& a_{1,2} & a_{1,3} \\ a_{2,1} & a_{2,2} & a_{2,3} \\ a_{3,1} & a_{3,2}& a_{3,3} \end{matrix} \right\} A=a1,1a2,1a3,1a1,2a2,2a3,2a1,3a2,3a3,3

B = { b 1 , 1 b 1 , 2 b 2 , 1 b 2 , 2 b 3 , 1 b 3 , 2 } B=\left\{ \begin{matrix} b_{1,1} &b_{1,2} \\ b_{2,1} & b_{2,2} \\ b_{3,1} & b_{3,2} \end{matrix} \right\} B=b1,1b2,1b3,1b1,2b2,2b3,2
C = { a 1 , 1 ∗ b 1 , 1 + a 1 , 2 ∗ b 2 , 1 + a 1 , 3 ∗ b 3 , 1 a 1 , 1 ∗ b 1 , 2 + a 1 , 2 ∗ b 2 , 2 + a 1 , 2 ∗ b 3 , 2 . . . . . . . . . . . . } C=\left\{ \begin{matrix} a_{1,1}*b_{1,1}+a_{1,2}*b_{2,1}+a_{1,3}*b_{3,1}& a_{1,1}*b_{1,2}+a_{1,2}*b_{2,2}+a_{1,2}*b_{3,2} \\ ... & ... \\ ... & ... \end{matrix} \right\} C=a1,1b1,1+a1,2b2,1+a1,3b3,1......a1,1b1,2+a1,2b2,2+a1,2b3,2......
C [ i ] [ j ] = ∑ a [ i ] [ k ] ∗ a [ k ] [ j ] ( k € [ 1 , m ] ) / / 意 思 就 是 把 A 的 第 i 行 和 B 的 第 j 列 分 别 相 乘 之 后 相 加 C[i][j]=∑a[i][k]*a[k][j] (k€[1,m]) //意思就是把A的第i行和B的第j列分别相乘之后相加 C[i][j]=a[i][k]a[k][j](k[1,m])//AiBj

矩阵乘法的具体实现
I matrix operator *(const matrix &x ,const matrix &y)
{
	matrix z;memset(z.a,0,sizeof(z.a));
	z.n=x.n;z.m=y.m;
	for(RI i=1;i<=z.n;i++)
	 for(RI k=1;k<=x.m;k++)
	  for(RI j=1;j<=z.m;j++)
	   z.a[i][j]=z.a[i][j]+x.a[i][k]*y.a[k][j];
	   
	return z;
}

矩阵快速幂

矩阵的快速幂和数的快速幂是一个道理!
并且矩阵乘法不一定任何时候都有交换律。因为交换后甚至不能保证第一个矩阵的列数等于第二个矩阵的行数。
但是,矩阵乘法有结合律。 A ∗ B ∗ C = A ∗ ( B ∗ C ) A*B*C=A*(B*C) ABC=A(BC)
这是一个最常用的运算律,使之可以用矩阵快速幂。

#include<bits/stdc++.h>
#define LL long long 
#define RI  register int 
#define RL register long long
#define maxn 150
#define I inline 
#define mod 1000000007

using namespace std;

I LL read()
{
     RL res=0,f=1;char ch=getchar();
     while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
     while(isdigit(ch)){res=(res<<1)+(res<<3)+(ch&15);ch=getchar();}
     return res*f;
} 
LL n,k;

struct matrix{
	LL a[maxn][maxn];
}m1,m2;

I matrix operator *(const matrix &x ,const matrix &y)
{
	matrix z;memset(z.a,0,sizeof(z.a));
	for(RI i=1;i<=n;i++)
	 for(RI k=1;k<=n;k++)
	  for(RI j=1;j<=n;j++)
	   z.a[i][j]=(z.a[i][j]+x.a[i][k]*y.a[k][j]%mod)%mod;
	   
	return z;
}

I void init()
{
     n=read();k=read();
     for(RI i=1;i<=n;i++)
     {
     	m2.a[i][i]=1;
		for(RI j=1;j<=n;j++)
		m1.a[i][j]=read();	
	 }
} 
I void print()
{
	for(RI i=1;i<=n;i++)
	{
		for(RI j=1;j<=n;j++)cout<<m2.a[i][j]<<' ';
		putchar('\n');
	}
}
I void fastpow()
{
	while(k)
	{
		if(k&1)m2=m2*m1;//把其乘到答案矩阵
		m1=m1*m1;//快速幂
		k>>=1;
	}
	return ;
}
int main()
{
	init();
	fastpow();
	print();
	return 0;
}

矩阵乘法优化dp

矩阵乘法优化一维dp

1.斐波那契数列

我们都知道斐波那契数列的递推式子是

f ( n ) = { 1 x ≤ 2 f ( n − 1 ) + f ( n − 2 ) x ≥ 3 f(n)= \begin{cases} 1& {x\le2}\\ f(n-1)+f(n-2)& {x\ge3} \end{cases} f(n)={1f(n1)+f(n2)x2x3

但是当题目让我们求斐波那契数列的第 1 0 9 10^9 109项怎么办?数组没法存,并且 O ( n ) O(n) O(n)还要超时,那么有没有一种方法可以缩短时间呢?
答案是能!就是运用到了我们上面的矩阵乘法
假设刚开始:
A = { f 1 f 2 } A=\left\{ \begin{matrix} f1& f2 \end{matrix} \right\} A={f1f2}
我们要推出下一步
C = { f 2 f 3 } C=\left\{ \begin{matrix} f2& f3 \end{matrix} \right\} C={f2f3}
我们构造一个B矩阵
B = { 0 1 1 1 } B=\left\{ \begin{matrix} 0& 1\\ 1 & 1 \end{matrix} \right\} B={0111}
发现只需要让 C = A ∗ B C=A*B C=AB
我们解决了一个问题就是:通过矩阵乘法也可以推出斐波那契数列的后面一项,但是好像每次乘矩阵B的复杂度也是 O ( n ) O(n) O(n)
A ∗ B ∗ B . . . . ∗ B = f ( n ) A*B*B....*B=f(n) ABB....B=f(n)
于是我们可以把中间的好多个乘矩阵B给简化成为矩阵快速幂
A ∗ B n − 2 = f ( n ) A*B^{n-2}=f(n) ABn2=f(n)
这样就可以在 O ( l o g n ) O(logn) O(logn)的情况下fast解决这道题目

#include<bits/stdc++.h>
#define LL long long 
#define RI  register int 
#define RL register long long
#define maxn 150
#define I inline 
#define mod 1000000007

using namespace std;

I LL read()
{
     RL res=0,f=1;char ch=getchar();
     while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
     while(isdigit(ch)){res=(res<<1)+(res<<3)+(ch&15);ch=getchar();}
     return res*f;
} 
LL n,k;

struct matrix{
	int n,m; 
	LL a[maxn][maxn];
}m1,m2;

I matrix operator *(const matrix &x ,const matrix &y)//矩阵乘法
{
	matrix z;memset(z.a,0,sizeof(z.a));
	z.n=x.n;z.m=y.m;
	for(RI i=1;i<=z.n;i++)
	 for(RI k=1;k<=x.m;k++)
	  for(RI j=1;j<=z.m;j++)
	   z.a[i][j]=(z.a[i][j]+x.a[i][k]*y.a[k][j]%mod)%mod;
	   
	return z;
}

I void init()
{
     n=read();
     if(n<=2){putchar('1');exit(0);}//初始化矩阵
     n-=2;
     m1.n=1;m1.m=2;
     m1.a[1][1]=1;m1.a[1][2]=1;
     m2.n=2;m2.m=2;
     m2.a[1][1]=0;m2.a[1][2]=1;
     m2.a[2][1]=1;m2.a[2][2]=1;
} 
I void fastpow()
{
	while(n)
	{
		if(n&1)m1=m1*m2;
		m2=m2*m2;
		n>>=1;
	}
	return ;
}
int main()
{
	init();
	fastpow();
	cout<<m1.a[1][2];
	return 0;
}

2.P1939 【模板】矩阵加速(数列)

题目大意就是
f ( n ) = { 1 x ≤ 3 f ( n − 1 ) + f ( n − 3 ) x ≥ 4 f(n)= \begin{cases} 1& {x\le3}\\ f(n-1)+f(n-3)& {x\ge4} \end{cases} f(n)={1f(n1)+f(n3)x3x4

我们和上面一样的做法
A = { f 1 f 2 f 3 } A=\left\{ \begin{matrix} f1& f2 & f3 \end{matrix} \right\} A={f1f2f3}
我们要推出下一步
C = { f 2 f 3 f 4 } C=\left\{ \begin{matrix} f2& f3 & f4 \end{matrix} \right\} C={f2f3f4}
我们构造一个B矩阵
B = { 0 0 1 1 0 0 0 1 1 } B=\left\{ \begin{matrix} 0& 0& 1\\ 1 & 0&0\\ 0&1&1 \end{matrix} \right\} B=010001101
就解决了

#include<bits/stdc++.h>
#define LL long long 
#define RI  register int 
#define RL register long long
#define maxn 150
#define I inline 
#define mod 1000000007

using namespace std;

I LL read()
{
     RL res=0,f=1;char ch=getchar();
     while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
     while(isdigit(ch)){res=(res<<1)+(res<<3)+(ch&15);ch=getchar();}
     return res*f;
} 
LL n,k;

struct matrix{
	int n,m; 
	LL a[maxn][maxn];
}m1,m2;

I matrix operator *(const matrix &x ,const matrix &y)
{
	matrix z;memset(z.a,0,sizeof(z.a));
	z.n=x.n;z.m=y.m;
	for(RI i=1;i<=z.n;i++)
	 for(RI k=1;k<=x.m;k++)
	  for(RI j=1;j<=z.m;j++)
	   z.a[i][j]=(z.a[i][j]+x.a[i][k]*y.a[k][j]%mod)%mod;
	   
	return z;
}

I void init()
{
     n-=3;
     m1.n=1;m1.m=3;
     m1.a[1][1]=1;m1.a[1][2]=1;m1.a[1][3]=1;
     m2.n=3;m2.m=3;
     m2.a[1][1]=0;m2.a[1][2]=0;m2.a[1][3]=1;
     m2.a[2][1]=1;m2.a[2][2]=0;m2.a[2][3]=0;
     m2.a[3][1]=0;m2.a[3][2]=1;m2.a[3][3]=1;
} 
I void fastpow()
{
	while(n)
	{
		if(n&1)m1=m1*m2;
		m2=m2*m2;
		n>>=1;
	}
	return ;
}
int T;
int main() 
{
	T=read();
	while(T--)
	{ 
	 n=read();if(n<=3){puts("1");continue;}
	init();
    
	fastpow();
	cout<<m1.a[1][3]<<endl;
	}
	return 0;
}

矩阵乘法优化二维dp

请添加图片描述
优化要满足一下四个条件

  1. 是二维的 f [ i ] [ j ] f[i][j] f[i][j]
  2. i − 1 i-1 i1转移到 i i i
  3. Σ 求 和 Σ求和 Σ
  4. 转移系数也就是上图中的 z [ k ] [ j ] z[k][j] z[k][j] i i i无关
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值