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

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

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

HDU 2044:一隻小蜜蜂

      不妨將圖示的蜂箱結構看成從1--—2——-3——…的一個“W”型樓梯。蜜蜂只能爬向右側相鄰的蜂房,不能反向爬行。可以等效地看成蜜蜂每次上樓梯可以走一級,也可以走兩級。

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

#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難題

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

      因爲RPG有三種顏色,可以先枚舉出當方格數爲1、2、3時的塗法種數。

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

                 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

 

原文出處:https://www.cnblogs.com/cs-whut/p/11552580.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章