致初學者(四):HDU 2044~2050 遞推專項習題解

      所謂遞推,是指從已知的初始條件出發,依據某種遞推關係,逐次推出所要求的各中間結果及最後結果。其中初始條件或是問題自己已經給定,或是經過對問題的分析與化簡後肯定。關於遞推的知識能夠參閱本博客中隨筆「遞推(一):遞推法的基本思想」。html

      HDU 2044~2050這7道題是針對初學者進行遞推學習的專項練習,下面給出它們的AC程序供參考。數組

HDU 2044:一隻小蜜蜂ide

      不妨將圖示的蜂箱結構當作從1--—2——-3——…的一個「W」型樓梯。蜜蜂只能爬向右側相鄰的蜂房,不能反向爬行。能夠等效地當作蜜蜂每次上樓梯能夠走一級,也能夠走兩級。學習

      易得遞推公式 : f[n]=f[n-1]+f[n-2] (n>2)  f[1]=1 f[2]=2。spa

#include <stdio.h>
int main()
{
    int n,a,b,i;
    __int64 f[51]={0,1,2};
    for (i=3;i<=50;i++)
        f[i]=f[i-1]+f[i-2];
    scanf("%d",&n);
    while (n--)
    {
        scanf("%d%d",&a,&b);
        printf("%I64d\n",f[b-a]);
    }
    return 0;
}
View Code

HDU 2045 不容易系列之(3)—— LELE的RPG難題3d

      設知足要求的n個方格的塗色方法數爲F(n)。code

      由於RPG有三種顏色,能夠先枚舉出當方格數爲一、二、3時的塗法種數。htm

      顯然,F(1)=3   (即R、P、G三種)blog

                 F(2)=6   (即RP、RG、PR、PG、GR、GP六種)字符串

                 F(3)=6   (即RPG、RGP、PRG、PGR、GRP、GPR六種)

      當方格的個數大於3時,n個方格的塗色方案能夠由n-1方格的塗色方案追加最後一個方格的塗色方案得出,分兩種狀況:

      (1)對於已按要求塗好顏色的n-1個方格,在F(n-1)種合法的塗色方案後追加一個方格(第n個方格),因爲合法方案的首尾顏色不一樣(即第n-1個方格的顏色不與第1個方格的相同),這樣,第n個方格的顏色也是肯定的,它一定是原n-1個方格的首尾兩種顏色以外的一種,所以,在這種狀況下的塗色方法數爲F(n-1)。

      (2)對於已按要求塗好顏色的n-2個方格,能夠在第n-1個方格中塗與第1個方格相同的顏色,此時因爲首尾顏色相同,這是不合法的塗色方案,但能夠在第n個方格中塗上一個合法的顏色,使其成爲方格長度爲n的合法塗色方案(注意:當n等於3時,因爲第1(3-2)個方格與第2(3-1)個方格顏色相同,第3個方格不論怎樣塗都不會合法,所以遞推的前提是n大於3),在第n個方格中能夠塗上兩種顏色(即首格外的兩種顏色,由於與它相連的第n-1個方格和第1個方格的顏色是同樣的),所以,在這種狀況下的塗色方法數爲2*F(n-2)。

       由此,可得遞推公式:F(n)= F(n-1) + 2*F(n-2)  (n>=4)

#include <stdio.h>
int main()
{
   int i,n;
   __int64 f[51]; 
   f[0]=0;    
   f[1]=3;     
   f[2]=6;    
   f[3]=6;     
   for(i=4;i<51;i++)         
       f[i]=f[i-1]+2*f[i-2];     
   while (scanf("%d",&n)!=EOF)
   {
       printf("%I64d\n",f[n]);
   }
   return 0;
}
View Code

HDU 2046 骨牌鋪方格

      設f[n]表示在2×n的一個長方形方格中用一個1× 2的骨牌鋪滿方格的方案數。顯然

      2×n的長方形方格能夠當作由2×(n-1)的長方形(方案數爲f[n-1])加1塊豎放的骨牌構成,也能夠當作由2×(n-2)的長方形(方案數爲f[n-2])加2塊橫放的骨牌構成。

      易得 遞推式爲: f[n]=f[n-1]+f[n-2] (n>2)。f[1]=1,f[2]=2。

#include <stdio.h>
int main()
{
    int n,i;
    __int64 f[51]={0,1,2};
    for (i=3;i<=50;i++)
        f[i]=f[i-1]+f[i-2];
    while (scanf("%d",&n)!=EOF)
    {
        printf("%I64d\n",f[n]);
    }
    return 0;
}
View Code

HDU 2047 阿牛的EOF牛肉串

      定義二維數組f[40][3],其中f[i][0]表示長度爲i,最後字符爲'E'的串的數目;

      f[i][1]表示長度爲i,最後字符爲'O'的串的數目;f[i][2]表示長度爲i,最後字符爲'F'的串的數目。

      顯然,對於長度爲i+1的字符串,若最後字符取'E'或'F',則其前面的一個字符任意,

      即  f[i+1][0]=f[i][0]+f[i][1]+f[i][2]

           f[i+1][2]=f[i][0]+f[i][1]+f[i][2]

     若最後字符取'O',則其前面的字符只能爲'E'或'F',因此

          f[i+1][1]=f[i][0]+f[i][2]

#include <stdio.h>
int main()
{
    int n,i;
    __int64 f[41][3];
    f[1][0]=1;
    f[1][1]=1;
    f[1][2]=1;
    for (i=2;i<40;i++)
    {
        f[i][0]=f[i-1][0]+f[i-1][1]+f[i-1][2];
        f[i][2]=f[i-1][0]+f[i-1][1]+f[i-1][2];
        f[i][1]=f[i-1][0]+f[i-1][2];
    }
    while (scanf("%d",&n)!=EOF)
    {
        printf("%I64d\n",f[n][0]+f[n][1]+f[n][2]);
    }
    return 0;
}
View Code

HDU 2048 神、上帝以及老天爺

      用遞推的方法推導錯排公式。

      設n我的抽n張紙條,紙條上的名字與本身的名字全不對應的方法數用F(n)表示,那麼F(n-1)就表示n-1我的抽n-1張紙條,紙條上的名字與本身的名字全不對應的方法。

      n張所有不對應的紙條能夠當作前n - 1張紙條再加1張紙條後,將最後1張紙條弄錯,弄錯的方式天然是與以前的紙條進行交換,交換的方式有兩種:

     (1)在前n-1個所有不對應的紙條中取任意一張進行交換。n-1張紙條所有不對應的方法數爲F(n-1),在n-1張紙條中任取一張的方法數爲n-1,所以,這種狀況下,方法數共有F(n-1)* (n-1)種。

      (2)在前n-1張紙條中,有n-2個全不對應,有1張正確,取正確的一張進行交換。n-1張紙條中只有一張對應正確的方法數有n-1,其他n-2張紙條全不對應的方法數有F(n-2), 所以,這種狀況下,方法數共有F(n-1)* (n-1)種。

       由此,可得錯排的遞推公式: F(n)=[F(n-2)+F(n-1)]*(n-1) 。

      初始狀況爲:F(1)=0  (只有1張紙條不可抽錯)

                           F(2)=1  (兩張紙條全不對應只有1種狀況,即正確的兩張交換)

#include <stdio.h>
int main()
{
   int i,c,n;
   __int64 f[21]={0,0,1}; 
   double ans;
   for (i=3;i<=20;i++)
   {
        f[i]=(f[i-1]+f[i-2])*(i-1);
    }
   scanf("%d",&c);
   while (c--)
   {
       scanf("%d",&n);
       ans=1.0*f[n];
       for (i=2;i<=n;i++)
           ans/=i;
       printf("%.2lf%%\n",100*ans);
   }
   return 0;
}
View Code

HDU 2049 不容易系列之(4)——考新郎

      先求出m(1<=m<=20)個元素的錯排數,用一維數組a來保存,其中a[i]保存i個元素的錯排數。

      再求在n個元素中挑選出m個元素的組合數c(n,m)。

      這樣,n對新婚夫婦中m個新郎找錯了新娘的狀況一共有c(n,m)*a[m]種。

#include <stdio.h>
int main()
{
    int t,n,m,p,i;
    __int64  c,sum,a[21]={0,0,1};
    for(i=3;i<21;i++)
    {
        a[i]=(a[i-1]+a[i-2])*(i-1);
    }
    scanf("%d",&t);
    while (t--)
    {
        scanf("%d%d",&n,&m);
        c=1;
        if (n-m>m)  p=n-m;
        else   p=m;
        for (i=n; i>p;i--)
           c=c*i;
        for (i=1;i<=n-p;i++)
           c=c/i;
        sum=c*a[m];
        printf("%I64d\n",sum);
    }
    return 0;
}
View Code

HDU 2050 折線分割平面

      設n-1條折線把空間劃分的區域數爲f(n-1)。

      現有n條折線,爲了讓增長的區域更多,新增的折線要和以前的n-1條折線的2*(n-1)條邊都相交,產生4*(n-1)條新的線段和2條射線,每條線段或射線產生一個新區域,可是折線相交的頭部的兩線段一共只能產生一個區域,因此新增區域的數量爲4*(n-1) -1+2, 即 4*(n-1) +1。 

      因此有遞推公式:

      f(n)=f(n-1)+4(n-1) + 1;

            =f(n-2)+4(n-2)+4(n-1)+2;

             .......

            =f(n-(n-1)) +4(n-(n-1))+4(n-(n-2))+......+4(n-1) + n-1;

            =f(1) +4(1+2+3+4+....+n-1)+n-1;

            =2+4((n-1)(n-1+1)/2)+n-1;

            =2n^2-n+1;

#include <stdio.h>
int main()
{
    int c;
    __int64 n;
    scanf("%d",&c);
    while (c--)
    {
        scanf("%I64d",&n);
        printf("%I64d\n",2*n*n-n+1);
    }
    return 0;
}
View Code
相關文章
相關標籤/搜索