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