POJ3070Fibonacci

矩阵乘法的入门题

我们先回忆一下通过递推如何求得fib的第n项,用三个变量t1=0,t1=1,t2=t1+t0,.....然后开始递推,但是这样的时间复杂度会很高,若用数组递推,则空间复杂度很高,所以我们要找一个时间和空间复杂度都很优秀的算法,至此,我们引入了矩阵乘法

顾名思义,矩阵乘法必然是矩阵之间的乘法,两个矩阵能相乘,当且仅当第一个矩阵的列数=第二个矩阵的行数,也就是说,一个n*m的矩阵,与一个m*h的矩阵相乘,会得到一个n*h的矩阵,新矩阵的第i,j位的数的句、计算公式为c(i,j)=Σ(a的第i行*b的第j列)a和b的元素可以一一对应,因为a的列数等于b的行数

然后我们想一下fib的递推公式fi=f(i-1)+f(i-2),然后我们需要构造一个初始矩阵f(fi-1,fi)->f(fi,fi+fi-1),也就是说我们的b矩阵与初始矩阵相乘后,得到的新矩阵的第一位是原初始矩阵的第二位,第二位是原矩阵的第一位与第二位的和,所以我们不难构造出,b矩阵={{0,1},{1,1}},也就是b[0][0]=0,b[0][1]=b[1][0]=b[1][1]=1,之后我们发现,即使这样,递推时间也没有减少,所以我们需要再优化时间,然后我们通过矩阵乘法的结合律->A*B*C=A*(B*C),发现我们可以先让b数组自乘n次,再乘初始矩阵,就可以得到fib(n),此时我们可以用快速幂来实现b数组自乘的加速,问题的解

代码

//By AcerMo
#include
#include
#include
#include
#include
using namespace std;
const int mod=10000;
int f[3];
int a[2][2];
int n;
void mul()
{
	int c[3]={0};
	for (int i=0;i<2;i++)
		for (int k=0;k<2;k++)
			c[i]=(c[i]+(long long int)f[k]*a[k][i])%mod;
	memcpy(f,c,sizeof(c));
	return ;
}
void muls()
{
	int c[2][2]={0};
	for (int i=0;i<2;i++)
		for (int j=0;j<2;j++)
			for (int k=0;k<2;k++)
				c[i][j]=(c[i][j]+(long long int)a[i][k]*a[k][j])%mod;
	memcpy(a,c,sizeof(c));
	return ;
}
int main()
{
	while (~scanf("%d",&n)&&n!=-1)
	{
		f[0]=0;f[1]=1;
		a[0][0]=0;a[0][1]=a[1][1]=a[1][0]=1;
		for (;n;muls(),n>>=1) if (n&1) mul();
		cout<

你可能感兴趣的:(矩阵乘法)