我們在算fn時最多不超過n-2個加法,
請寫作一個速度更快的程式,或許您可以用乘法。
如果每一個乘法用m單位時間,每一個加法用p單位時間,
於是非遞迴的寫法因為最多有n-2個加法,因此最多用(n-2)p時間。
請問,您的改良程式要用多少時間?
假設只考慮加法與乘法而已。
答:
令上面的矩陣為M,在算M^(n-2)時,
我們可以依照n的奇偶數來像之前算m^n一樣來化簡。
單位矩陣 r=0
M^r = (M^k)^2 r=2k
M*(M^2k) r=2k+1
因此使用遞迴,我們用2 log n次矩陣相乘就可以得到M^n了。(log底數為2)
2x2的矩陣相乘一次需要8個乘法,4個加法,
所以最多總時間不超過(2 log n)*(8m+4p)。
當n夠大的時候,n > log n,其他的m和p和n無關所以可以視為常數。
所以當n非常大了,此方法所用的時間就小於(n-2)p,因此會比較快。
Code:
#include <stdio.h> #include <stdlib.h> /** (n-2) +--------+ +--------+ | aa bb | | a b | | | = | | | cc dd | | c d | +--------+ +--------+ */ void matrix_power(unsigned long a, unsigned long b, unsigned long c, unsigned long d, int n, unsigned long *aa, unsigned long *bb, unsigned long *cc, unsigned long *dd ) { unsigned long xa, xb, xc, xd; if(n==1) *aa = a, *bb = b, *cc = c, *dd = d; else if(n & 0x01 == 1) // n = 2k+1, break into m*m^2k { // compute m^2k, then multiply m matrix_power(a, b, c, d, n-1, &xa, &xb, &xc, &xd); *aa = a*xa + b*xc; *bb = a*xb + b*xd; *cc = c*xa + d*xc; *dd = c*xb + d*xd; } else // n = 2k, break into (m^k) * (m^k) { matrix_power(a, b, c, d, n>>1, &xa, &xb, &xc, &xd); *aa = xa*xa + xb*xc; *bb = xa*xb + xb*xd; *cc = xc*xa + xd*xc; *dd = xc*xb + xd*xd; } } unsigned long fibonacci(int n) { unsigned long a, b, c, d; if( n <= 2 ) return 1; else { matrix_power(1UL, 1UL, 1UL, 0UL, n-2, &a, &b, &c, &d); return a + b; } } int main(int argc, char *argv[]) { int n; for(n = 1; n <= 20; n++) printf("f(%d) = %ld\n", n, fibonacci(n)); system("PAUSE"); return 0; }
沒有留言:
張貼留言