数学知识-矩阵乘法
矩陣乘法原理
? ? ? ? 注意這里的矩陣是《線性代數》中的矩陣,矩陣乘法指的是兩個內標相同的矩陣相乘得到新矩陣的過程。
? ? ? ?設有矩陣為矩陣,有矩陣為矩陣,則矩陣相乘結果如下:
?? ?
矩陣乘法應用
? ? ? ? 矩陣乘法的應用在于能夠加快遞推速度,對于一個n*s的矩陣,可以化成程序中的二維數組,則代表第行第列元素(下標從0開始)
? ? ? ? 對于常規遞推,通常是有的形式,也就是常說的:大規模問題需要分解成小問題,并且借助小問題規模的答案進行解決。
? ? ? ? 矩陣乘法的原理是通過將有限個預備狀態用矩陣存放,并且用另一個對應矩陣作為系數,在
通過矩陣運算來減少線性遞推。
斐波那契數列
? ? ? ? 斐波那契數列指的是第一項第二項均為1,第三項開始每項都等于前兩項之和的數列。
? ? ? ? 設為第個斐波那契數列的值,顯然有,如果考慮用程序實
現的話,那么應該是,其中第一項第二項均已賦初值為1,這樣可以求解到我們所需要的第個斐波那契數的值,由于時間復雜度為,也就是最多能進行級別的運算,如果超過這個級別的數據規模就會超時。
? ? ? ? ?考慮矩陣乘法加速遞推,步驟如下
(1)令? 得到
(2)考慮如何把,也就是思考
(3)顯然我們希望把第二項放到第一項,然后原本的第一項變成原來的第一項和第二項之和
(4)那么則我們希望通過一個矩陣,有
(5)有了結果,逆推矩陣A很簡單,因為我們可以通過乘法的本質來逆推得到
? ? ? ? 考慮逆推出矩陣A的結構,步驟如下:
(1)首先矩陣A的外標肯定是1,否則不符合矩陣相乘的規則,那么應該是一個2*n的矩陣
再由1*2 *A=1*2 ,說明內標也是2,(因為n*s × s*m=n*m)
(2)設,由矩陣乘法得到:
,
聯立解得:
? ? ? ? A12=1,A22=1,A11=0,A21=1;
? ? ? ? 考慮程序實現矩陣快速遞推,步驟如下:
(1)由于?,此時借助快速冪的思想
當n為奇數的時候,等價于求,為偶數時,等價于求,這樣可以在對數的復雜度
內求出。當然我們可以為奇數的時候讓Fn與其相乘,為偶數時其自乘。
代碼如下:
#include <iostream> #include <cstring> typedef long long ll; using namespace std; const int N=10007; void mul(int f[2],int a[2][2]){int c[2];memset(c,0,sizeof c);for(int j=0;j<2;j++){for(int k=0;k<2;k++){c[j]=(c[j]+(ll)f[k]*a[k][j])%N;//c[i][j]=f[i][k]*a[k][j]//由于f只有一層 所以只需要枚舉j和k }}memcpy(f,c,sizeof c);return; }void mulself(int a[2][2]){int c[2][2];memset(c,0,sizeof c);for(int i=0;i<2;i++){for(int j=0;j<2;j++){for(int k=0;k<2;k++){//a有兩層 需要枚舉i,j,然后再枚舉kc[i][j]=(c[i][j]+(ll)a[i][k]*a[k][j])%N;}}}memcpy(a,c,sizeof c);//備份拷貝,如果邊決策邊賦值會影響 return; }int main(){int n;scanf("%d",&n);int a[2][2]={{0,1},{1,1}};int f[2]={0,1};while(n){if(n&1)mul(f,a);mulself(a);n/=2;}printf("%d",f[0]);}時間復雜度:可以理解成將只有一次操作執行了mul,其余都在進行快速冪,這樣來看
mul操作是常數級別,只有mulself是需要執行logn次的,所以是
? ? ? 我在藍橋杯官方訓練系統中找到了斐波那契的模板題,時間對比如下:
(普通遞推)
(使用矩陣相乘)
最后:矩陣相乘大概就是用矩陣的角度看待遞推,將遞推的變化盡可能化成矩陣相乘后的結果,
不過設出F和A并不容易。
總結
- 上一篇: 灰度化之后的图片呈绿色
- 下一篇: 审批延迟、高通愿接盘,英伟达400亿美元