算法之動態規劃(遞推求解一)

這篇博客主要講的是動態規劃入門,即動態規劃的思想,而且再講解動態規劃的最簡單的一個方法。spa

首先,什麼是動態規劃?code

  動態規劃是經過拆分問題,定義問題狀態和狀態之間的關係,使得問題可以以遞推(或者說分治)的方式去解決。其實就是分解問題,分而治之。可能這樣說你們都不太理解,其實這個有點相似於數學中的遞推公式。來舉一個簡單的例子,看下邊這個題:blog

  N階樓梯上樓問題:一次能夠走兩階或一階,問有多少種上樓方式。遞歸

  這就是動態規劃就簡單的一個列子。拿到這個題,你們是否是都有點迷,這個到底怎麼作?是否是沒有思路,那麼按照動態規劃思想,咱們能夠先分析下問題,每次都有兩種跳法,分別是一階或者兩階,那麼若是當前是第n個臺階,那麼跳法是否是是(n-1)臺階的跳法數加上(n-2)臺階的跳法數?若是划算成公式是F(n) =  F(n-1)+F(n-2)。F(n)表明第n階臺階的跳法的數量。博客

  這不就至關於找到了一個遞推公式,而後來進行計算。具體的代碼實現以下(採用的是非遞歸):數學

#include <stdio.h>    
     
int main()    
{    
        int i,N;    
        long long a[90];    
        while(~scanf("%d",&N))    
        {                 
                a[1]=1;    
                a[2]=2;    
                for(i=3;i<=N;i++)    
                        a[i]=a[i-1]+a[i-2];    
                printf("%lld\n",a[N]);    
        }    
             
        return 0;    
             
}   

 

下邊再舉一個列子來輔助理解:io

  n封信放入n個信封,要求所有放錯,共有多少种放法,記n個元素的錯排總數爲f(n)入門

  對於這個題,咱們能夠採用和上述同樣的思路,咱們是否要考慮下找一個相似的遞推公式等來解決。思路以下:class

  在任意一種錯裝方案中,假設n號信封裏裝的是k號信封的信,而n號信封裏的信則裝在m號信封裏。咱們按照k和m的等值與否將總的錯裝方式分爲兩類。  若k不等於m,交換n號信封和m號信封的信後,n號信封裏裝的剛好是對應的信,而m號信封中錯裝k號信封裏的信,即除n號信封外其他n-1個信封 所有錯裝,其錯裝方式等於 F[n - 1],又因爲m的n-1個可能取值,這類錯裝方式總數爲(n - 1)* F[n - 1]。也能夠理解爲,在 n-1個信封錯裝的 F[n - 1]種方式的基礎上,將n號信封所裝的信與n - 1個信封中任意一個信封(共有 n-1 中選 擇)所裝的信作交換後,獲得全部信封所有錯裝的方式數。另外一種狀況,若 k 等於 m,交換 n 號信封和 m 號信封的信後,n 號信封和 m 號信封裏裝的剛好是對應的信,這樣除它們以外剩餘的 n-2 個信封所有錯裝,其 錯裝方式爲 F[n - 2],又因爲 m 的 n-1 個取值,這類錯裝方式總數爲(n - 1)* F[n - 2]。也能夠理解爲,在 n - 2 個信封所有錯裝的基礎上,交換最後兩個信封中的 信(n 號信封和 1 到 n-1 號信封中任意一個,共有 n-1 種選擇),使全部的信封所有 錯裝的方式數。  綜上所述,F[n] = (n - 1) * F[n - 1] + (n - 1) * F[n - 2]。這就是錯排公式。基礎

  具體代碼以下:

#include <stdio.h>
Long long F[21]; //數值較大選用long long
int main () {
  F[1] = 0;
  F[2] = 1; //初始值
  for (int i = 3;i <= 20;i ++)
    F[i] = (i - 1) * F[i - 1] + (i - 1) * F[i - 2]; //遞推求得數列每個數字
  int n;
  while (scanf ("%d",&n) != EOF) {
    printf("%lld\n",F[n]); //輸出
  }
  return 0;
}
相關文章
相關標籤/搜索