1. 程式人生 > >遞迴與動態規劃---斐波那契系列問題的遞迴,動態規劃與矩陣乘法

遞迴與動態規劃---斐波那契系列問題的遞迴,動態規劃與矩陣乘法

【題目】

  1. 給定整數N,返回斐波那契數列的第N項
  2. 假設農場中成熟的母牛每年只會生一頭小母牛,並且永遠不會死。第一年農場有1只成熟的牛,從第二年開始,母牛開始生小母牛。每隻小母牛3年之後 成熟又可以生小母牛。給定整數N,返回N年後牛的數量。

【基本思路】
  原問題。O(2^N)的方法。斐波那契數列為1,1,2,3,5,8……,也就是除第一項和第二項以外,對於第N項,有F(N) = F(N-1) + f(N-2),於是可以很輕鬆的寫出暴力遞迴的程式碼。下面是使用python3.5實現的程式碼:
  

遞迴。時間複雜度(2^N)
def fibonacci1(n):
    if
n < 1: return 0 if n == 1 or n == 2: return 1 return fibonacci1(n-1) + fibonacci1(n-2)

  O(N)的方法。斐波那契可以從左到右依次求出每一項的值,那麼可以順序計算求到第N項即可。下面是使用python3.5實現的程式碼:

遞迴。時間複雜度(2^N)
def fibonacci2(n):
    if n < 1:
        return 0
    if n == 1 or n == 2:
        return 1
    pre = 1
cur = 1 for i in range(3, n+1): tmp = cur cur = pre + cur pre = tmp return cur

  O(logN)的方法。矩陣乘法推導如下(字醜見諒)
      這裡寫圖片描述

  所以現在的問題就變成了如何使用最快的方法求一個矩陣的N次方,而求一個矩陣的N次方明顯可以在O(logN)時間內完成。為了表述方便,現在使用一個整數N次方的例子來說明,矩陣的求解過程類似。
  假設一個整數是10,如何快速的求解10的75次方。

  1. 75的二進位制形式為1001011.

  2. 10的75次方 = 10

    64108102101
    在這個過程中,我們先求出101,然後根據101求出102,再根據102求出104,……,最後再根據1032求出1064,即75的二進位制形式總共有多少位,我們就使用幾次乘法。

  3. 在步驟2進行的過程中,把應該累乘的值相乘即可。即二進位制形式中是1的位置的相乘,這樣就得到結果1064108102101

下面是使用python3.5實現的程式碼:

#矩陣乘法方法。時間複雜度(logN)
def fibonacciUseMatrix(n):
    def matrixPower(m, p):
        res = [[0 if i != j else 1 for i in range(len(m[0]))] for j in range(len(m))]  #單位矩陣
        tmp = m
        while p > 0:
            if p & 1 != 0:
                res = muliMatrix(res, tmp)
            tmp = muliMatrix(tmp, tmp)
            p >>= 1
        return res

    def muliMatrix(m1, m2):
        res = [[0 for i in range(len(m2[0]))] for j in range(len(m1))]
        for i in range(len(m1)):
            for j in range(len(m2[0])):
                for k in range(len(m1[0])):
                    res[i][j] += m1[i][k] * m2[k][j]
        return res

    if n < 1:
        return 0
    if n == 1 or n == 2:
        return 1
    base = [[1,1],[1,0]]
    res = matrixPower(base, n-2)
    return res[0][0] + res[0][1]

母牛數量問題。所有牛都不會死,所以第N-1年的牛都會活到第N年。同時,所有成熟的母牛都會生一隻小母牛,那麼成熟牛的數量怎麼計算呢?就是第N-3年的所有牛,到第N年肯定都是成熟的牛,期間出生的牛肯定都沒有成熟。所以C(N) = C(N-1) + C(N-3)。該問題同樣也可以使用矩陣乘法的方式,只不過這裡是三階遞推數列,原理同上,詳情見如下程式碼。

下面是使用python3.5實現的程式碼。

#母牛數量問題
#遞迴
def fibonacci3(n):
    if n < 1 :
        return 0
    if n == 1 or n == 2 or n == 3:
        return n
    return fibonacci3(n-1) + fibonacci3(n-3)

#動態規劃
def fibonacci4(n):
    if n < 1:
        return 0
    if n == 1 or n == 2 or n == 3:
        return 3
    prepre = 1
    pre = 2
    cur = 3
    for i in range(4, n+1):
        tmp = cur
        cur = prepre + cur
        prepre = pre
        pre = tmp
    return cur

#矩陣乘法
def fibonacciUseMatrix2(n):
    def matrixPower(m, p):
        res = [[1 if i == j else 0 for i in range(len(m[0]))] for j in range(len(m))]
        tmp = m
        while p > 0:
            if p & 1 != 0:
                res = muliMatrix(res, tmp)
            tmp = muliMatrix(tmp, tmp)
            p >>= 1
        return res

    def muliMatrix(m1, m2):
        res = [[0 for i in range(len(m2[0]))] for j in range(len(m1))]
        for i in range(len(m1)):
            for j in range(len(m2[0])):
                for k in range(len(m1[0])):
                    res[i][j] += m1[i][k] * m2[k][j]
        return res

    if n < 1:
        return 0
    if n == 1 or n ==2 or n == 3:
        return n
    base = [[1,1,0], [0,0,1], [1,0,0]]
    res = matrixPower(base, n-3)
    return 3 * res[0][0] + 2 * res[1][0] + res[2][0]