1. 程式人生 > >矩陣乘法與斐波那契

矩陣乘法與斐波那契

矩陣乘法

A*B,只有當A的列數等於B的行數時才有意義,即A為nm的矩陣,B為mL的矩陣。矩陣的乘法定義如下:

[adbecf]gikhjl=[ag+bi+ckdg+ei+fkah+bj+cldh+ej+fl]
Ci,j=k=1mA[i][k]+B[k][j]
由定義可知,矩陣乘法滿足結合律,但不滿足交換律。

應用

矩陣乘法可以用來優化很多線性遞推式,下面以求斐波那契為例。
我們知道,f[n]=f[n1]+f[n2],可以構造一個矩陣A,使得A*[f[n]f[n1]]=[f[n]+f[n1]f[n]],這樣,初始矩陣[10]每乘一次A陣列,矩陣的第一位就往下推了一個,那麼,要求第n項只要乘n-1次,而由於矩陣的乘法是滿足結合律的,所以可以用快速冪來求矩陣A的n-1次冪,複雜度大大降低。
那麼,如何設計矩陣A呢?
顯然,A是一個2*2的矩陣,設A

=[acbd]A[f[n]f[n1]]=[af[n]+bf[n1]cf[n]+df[n1]],顯然,a=1,b=1,c=1,d=0,這樣,我們就構造出

A=[1110]
剩下的事就交給快速冪了。
下面附上poj3070的程式碼:
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxn 5
#define tt 10000
using namespace std;
inline char nc(){
    static char buf[100000],*i=buf,*j=buf;
    return
i==j&&(j=(i=buf)+fread(buf,1,100000,stdin),i==j)?EOF:*i++; } inline int _read(){ char ch=nc();int sum=0,p=1; while(ch!='-'&&!(ch>='0'&&ch<='9'))ch=nc(); if(ch=='-')p=-1,ch=nc(); while(ch>='0'&&ch<='9')sum=sum*10+ch-48,ch=nc(); return sum*p; } struct
matrix{ int n,m,a[maxn][maxn]; matrix operator *(matrix&b){ matrix c;c.n=n;c.m=b.m; for(int i=1;i<=c.n;i++) for(int j=1;j<=c.m;j++){ c.a[i][j]=0; for(int k=1;k<=m;k++) (c.a[i][j]+=a[i][k]*b.a[k][j])%=tt; } return c; } }; int n; matrix G,ans; matrix power(matrix x,int y){ if(y==1)return x; matrix c=power(x,y>>1); if(y&1)return c*c*x; else return c*c; } int main(){ freopen("fib.in","r",stdin); freopen("fib.out","w",stdout); n=_read(); while(n!=-1){ G.n=G.m=2;G.a[1][1]=G.a[1][2]=G.a[2][1]=1;G.a[2][2]=0; ans.n=2;ans.m=1;ans.a[1][1]=1;ans.a[2][1]=0; if(n==0){ printf("0\n");n=_read(); continue; } if(n==1){ printf("1\n");n=_read(); continue; } G=power(G,n-1); ans=G*ans; printf("%d\n",ans.a[1][1]); n=_read(); } return 0; }