簡體   English   中英

動態編程中的第n個斐波那契數

[英]nth Fibonacci number in dynamic programming

每個人都知道斐波那契數列的邏輯

Fib0 = 0
Fib1 = 1
Fibn = Fibn-1 + Fibn-2 , n > 1

我的問題是我必須計算fib(n)%(100000000+7)並且輸出應根據n

for n=0 output 1

for n=5 output 5

for n=10 output 55

for n=100 output 24278230

我也成功地在scala使用tail recursion進行了編碼

def fi( n : Int) : Long = { 
  def fib_tail( n: Int, a:Int, b:Int): Int = n match {
    case 0 => a 
    case _ => fib_tail( n-1, b, (a+b))
  }
  return fib_tail( n, 0, 1)
}


   l.map(x=> println(fi(x)%((math.pow(10, 8)).toInt +7  )))

它適用於0,1,5,10,但它給出了100的錯誤輸出,我希望24278230100

任何人都給我一些想法以獲取此輸出

我的答案是線性遞歸序列的某種通用解決方案。 您需要一些基本的代數知識才能完全理解它。

讓我們有一個向量

然后將其與矩陣相乘

我們會收到:

因此,當我們將向量與該矩陣相乘時,我們將收到下一個斐波那契數。 但是如果將向量乘以T 2會發生什么?

這樣,我們在下一個(第(n + 3)個)之后構造了斐波那契數。 現在,如果我們從向量中的前兩個斐波那契數開始並將其乘以T n-1 ,將會得到什么?

因此,通過將向量乘以矩陣T(提高到第(n-1)次冪),我們可以獲得第n個斐波那契數。 我們可以通過平方求冪,在時間O(log n)中計算T n-1 當然,我們應該以10 8 + 7為模進行所有計算。

這是我的實現的鏈接(使用Java): http : //pastie.org/8519742

對於所有n的正值,直到2 10 8,該算法都應該很好且快速地工作。

該方法的示例運行時間(使用與Peter Lawrey的答案相同的時間度量):

fib(1,000,000,000,000,000,000) is 8,465,404 took us 1022.8 to calculate
fib(100,000,000,000,000,000) is 60,687,801 took us 325.7 to calculate
fib(10,000,000,000,000,000) is 9,115,009 took us 247.2 to calculate
fib(1,000,000,000,000,000) is 8,361,917 took us 233.3 to calculate
fib(100,000,000,000,000) is 11,279,600 took us 218.3 to calculate
fib(10,000,000,000,000) is 72,758,000 took us 6027.7 to calculate
fib(1,000,000,000,000) is 82,461,898 took us 184.2 to calculate
fib(100,000,000,000) is 60,584,292 took us 180.4 to calculate
fib(10,000,000,000) is 68,453,509 took us 162.0 to calculate
fib(1,000,000,000) is 90,703,191 took us 145.4 to calculate
fib(100,000,000) is 21 took us 131.3 to calculate
fib(10,000,000) is 60,722,758 took us 112.0 to calculate
fib(1,000,000) is 72,117,251 took us 99.8 to calculate
fib(100,000) is 33,178,829 took us 92.3 to calculate
fib(10,000) is 49,520,320 took us 70.8 to calculate
fib(1,000) is 95,802,669 took us 60.1 to calculate
fib(100) is 24,278,230 took us 39.3 to calculate
fib(10) is 55 took us 27.0 to calculate
fib(1) is 1 took us 16.3 to calculate

但是,盡管如此,這並不是解決問題的最快算法。 眾所周知,斐波那契數在某些模塊下具有周期性殘基。 在Wikipedia條目上引用斐波那契數字:

可以看出,如果斐波那契序列的成員取mod n,則所得序列必須是周期性的,周期最多為n 2 -1。

換句話說,如果您找到該時間段(例如, 烏龜和野兔算法 -線性復雜度),則還可以找到每個斐波那契數模10 8 +7的結果。

這是我知道的計算fib%mod的最快方法,但是您只能看到大約1000+的差異

public static void main(String[] args) {
    long mod = 100_000_007;
    for (int i = 100_000_000; i > 0; i /= 10) {
        long start = System.nanoTime();
        final long l = fibMod3(i, mod);
        long time = System.nanoTime() - start;
        System.out.printf("fib(%,d) %% %,d is %,d took %.1f us to calculate%n", i, mod, l, time / 1e3);
    }
}

// use a simple loop and % each time.
public static long fibMod(int n, long mod) {
    long a = 1, b = 1;
    if (n <= 2) return 1;
    while (n-- > 2) {
        long c = a + b;
        a = b;
        b = c % mod;
    }
    return b;
}

// mod is very expensive so only do this on every third iteration.
public static long fibMod3(int n, long mod) {
    long a = 1, b = 1;
    if (n <= 2) return 1;
    while (n > 5) {
        long c = a + b;
        a = b + c;
        b = (c + a) % mod;
        n -= 3;
    }
    while (n > 2) {
        long c = a + b;
        a = b;
        b = c;
        n--;
    }
    return b % mod;
}

版畫

fib(100,000,000) % 100,000,007 is 21 took 546460.1 us to calculate
fib(10,000,000) % 100,000,007 is 60,722,758 took 54079.6 us to calculate
fib(1,000,000) % 100,000,007 is 72,117,251 took 5274.9 us to calculate
fib(100,000) % 100,000,007 is 33,178,829 took 506.0 us to calculate
fib(10,000) % 100,000,007 is 49,520,320 took 50.8 us to calculate
fib(1,000) % 100,000,007 is 95,802,669 took 5.2 us to calculate
fib(100) % 100,000,007 is 24,278,230 took 0.7 us to calculate
fib(10) % 100,000,007 is 55 took 0.3 us to calculate
fib(1) % 100,000,007 is 1 took 0.3 us to calculate

代碼預熱后,fib(100)耗時0.7微秒。 如果循環增加大小,它甚至不會被編譯,大約需要3微秒。

我已經用C ++編寫了代碼,並且效果很好。

LL fi(int n, LL a, LL b) {
   if (n == 0) {
     return a;
  } else {
     return fi(n-1, b, (a+b) % 100000007);
   }
}

您應在此處修改:fib_tail(n-1,b,(a + b)%MOD),否則結果將超出Long的范圍。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM