斐波那契數(shù)列 優(yōu)化矩陣求法實(shí)例
在做編程題目的時(shí)候經(jīng)常會(huì)遇到“斐波那契數(shù)列”相關(guān)的題目,尤其在做OJ中。下面說(shuō)一些方法:
(一)遞歸
遞歸是最慢的會(huì)發(fā)生重復(fù)計(jì)算,時(shí)間復(fù)雜度成指數(shù)級(jí)。
long long fac(int n)
{
if(n==1) return 1;
else if(n==2) return 2;
else return fac(n-1)+fac(n-2);
}
(二)循環(huán)
利用臨時(shí)變量來(lái)保存中間的計(jì)算過(guò)程,加快運(yùn)算。
long long fac(int n)
{
long long a=1,b=2,c;
if(n==1) return 1;
else if(n==2) return 2;
else
{
for(int i=3;i<=n;i++)
{
c=a+b; a=b; b=c;
}
}
return b;
}
(三)矩陣乘法+空間換時(shí)間(減少乘法,取模運(yùn)算)
數(shù)列的遞推公式為:f(1)=1,f(2)=2,f(n)=f(n-1)+f(n-2)(n>=3)
用矩陣表示為:

進(jìn)一步,可以得出直接推導(dǎo)公式:

由于矩陣乘法滿(mǎn)足結(jié)合律,在程序中可以事先給定矩陣的64,32,16,8,4,2,1次方,加快程序的執(zhí)行時(shí)間。(有些題目需要取模運(yùn)算,也可以事先進(jìn)行一下)。給定的矩陣次冪,與二進(jìn)制有關(guān)是因?yàn)?,如下的公式存在解,滿(mǎn)足Xi={0或1}:

為了保證解滿(mǎn)足 Xi={0或1},對(duì)上述公式的求解從右向左,即求解順序?yàn)閄n,Xn-1,Xn-2,....,X1,X0。
完整代碼實(shí)現(xiàn)如下:
///求解fac(n)%100000,其中n為大于等于3的正整數(shù)
#include<stdio.h>
#include<math.h>
long long fac_tmp[6][4]={ ///存放矩陣次冪
///位置:00 01 10 11
{24578,78309,78309,46269}, ///32次冪%100000
{1597,987,987,610}, ///16次冪%100000
{34,21,21,13}, ///8次冪%100000
{5,3,3,2}, ///4次冪%100000
{2,1,1,1}, ///2次冪%100000
{1,1,1,0}, ///1次冪%100000
};
void fac(int);
int main()
{
int n;
scanf("%d",&n);
fac(n);
return 1;
}
void fac(int k) ///k>=3
{
int i;
long long t00=1,t01=1,t10=1,t11=0; ///表示矩陣的1次冪
long long a,b,c,d;
k=k-3; ///公式中是n-2次冪,(t00,t01,t10,t11)表示1次冪。所以一共減3次
for(i=k;i>=32;i=i-32) ///對(duì)于大于等于32的k;
{
a=(t00*fac_tmp[0][0]+t01*fac_tmp[0][2])%100000;
b=(t00*fac_tmp[0][1]+t01*fac_tmp[0][3])%100000;
c=(t10*fac_tmp[0][0]+t11*fac_tmp[0][2])%100000;
d=(t10*fac_tmp[0][1]+t11*fac_tmp[0][3])%100000;
t00=a; t01=b; t10=c;t11=d;
}
i=4;
while(i>=0) ///對(duì)于小于32的k(16,8,4,2,1);
{
if(k>=(long long)pow(2,i)) ///如果k大于某一個(gè)2的次冪
{
a=(t00*fac_tmp[5-i][0]+t01*fac_tmp[5-i][2])%100000; ///(5-i):矩陣的2的i次冪在數(shù)組fac_tmp中的位置為fac_tmp[5-i]
b=(t00*fac_tmp[5-i][1]+t01*fac_tmp[5-i][3])%100000;
c=(t10*fac_tmp[5-i][0]+t11*fac_tmp[5-i][2])%100000;
d=(t10*fac_tmp[5-i][1]+t11*fac_tmp[5-i][3])%100000;
t00=a; t01=b; t10=c;t11=d;
k=k-(int)pow(2,i);
}
i--;
}
a=(t00*2+t01*1)%100000;
printf("%lld\n",a);
}
- java實(shí)現(xiàn)fibonacci數(shù)列學(xué)習(xí)示例分享(斐波那契數(shù)列)
- java實(shí)現(xiàn)斐波那契數(shù)列的3種方法
- C++輸出斐波那契數(shù)列的兩種實(shí)現(xiàn)方法
- 解析分別用遞歸與循環(huán)的方式求斐波那契數(shù)列的實(shí)現(xiàn)方法
- 遞歸形式與非遞歸形式的斐波那契數(shù)列的用法分析
- c#斐波那契數(shù)列(Fibonacci)(遞歸,非遞歸)實(shí)現(xiàn)代碼
- 基于使用遞歸推算指定位數(shù)的斐波那契數(shù)列值的解決方法
- php處理斐波那契數(shù)列非遞歸方法
- python求斐波那契數(shù)列示例分享
相關(guān)文章
C++和python實(shí)現(xiàn)單鏈表及其原理
這篇文章主要介紹了C++和python實(shí)現(xiàn)單鏈表及其原理,單鏈表是鏈表家族中的一員,每個(gè)節(jié)點(diǎn)依舊由數(shù)據(jù)域(data)和指針域(next)組成,鏈表的具體概念下面文章將詳細(xì)介紹,需要的小伙伴可以參考一下2022-03-03C語(yǔ)言數(shù)據(jù)結(jié)構(gòu)之 折半查找實(shí)例詳解
這篇文章主要介紹了C語(yǔ)言數(shù)據(jù)結(jié)構(gòu)之 折半查找實(shí)例詳解的相關(guān)資料,需要的朋友可以參考下2017-06-06C語(yǔ)言編程數(shù)據(jù)結(jié)構(gòu)線性表之順序表和鏈表原理分析
本篇文章是C語(yǔ)言編程篇主要為大家介紹了C語(yǔ)言編程中的數(shù)據(jù)結(jié)構(gòu)線性表,文中附含豐富的圖文示例代碼為大家詳解了線性表中的順序表和鏈表,有需要的朋友可以借鑒參考下2021-09-09C語(yǔ)言詳解實(shí)現(xiàn)鏈?zhǔn)蕉鏄?shù)的遍歷與相關(guān)接口
二叉樹(shù)的鏈?zhǔn)酱鎯?chǔ)結(jié)構(gòu)是指,用鏈表來(lái)表示一棵二叉樹(shù),即用鏈來(lái)指示元素的邏輯關(guān)系。通常的方法是鏈表中每個(gè)結(jié)點(diǎn)由三個(gè)域組成,數(shù)據(jù)域和左右指針域,左右指針?lè)謩e用來(lái)給出該結(jié)點(diǎn)左孩子和右孩子所在的鏈結(jié)點(diǎn)的存儲(chǔ)地址2022-04-04COLORREF,COLOR,RGB,CString的轉(zhuǎn)化總結(jié)分析
實(shí)際的軟件開(kāi)發(fā)過(guò)程中,常需要用到非.net平臺(tái)的代碼。這時(shí)候就可能碰到ColorRef(也就是以int類(lèi)型代表的顏色值或是以DWORD值表示的顏色)。這跟.net平臺(tái)下的顏色的相互轉(zhuǎn)換MS并沒(méi)有直接實(shí)現(xiàn)2013-09-09構(gòu)造函數(shù)不能聲明為虛函數(shù)的原因及分析
構(gòu)造函數(shù)不需要是虛函數(shù),也不允許是虛函數(shù),因?yàn)閯?chuàng)建一個(gè)對(duì)象時(shí)我們總是要明確指定對(duì)象的類(lèi)型,盡管我們可能通過(guò)實(shí)驗(yàn)室的基類(lèi)的指針或引用去訪問(wèn)它但析構(gòu)卻不一定,我們往往通過(guò)基類(lèi)的指針來(lái)銷(xiāo)毀對(duì)象2013-10-10