一、特殊情況
1.問題提出
一個頑猴在一座有30級台階的小山上爬山跳躍。上山一步可上跳1級或3級,求上山有多少種跳法。
2.解題思路
達到第30級之前位於哪一階呢??有兩種情況,其一是第29級,一步跳一階到達,其二是第27級,一步跳三階到達。
所以有:
f(30) = f(29) + f(27)
其他以此類推,一般地有遞推關係:
f(k) = f(k - 1) + f(k - 3)
而初始條件為:
f(1) = 1
f(2) = 1 (1+1)
f(3) = 2 (1+1+1, 3)
3.程式碼
// 猴子爬山n級台階,一步跨1級或3級<br />#include <stdio.h></p><p>int main(void)<br />{<br />int k, n;<br />long f[1000];// f[i]存放跳i級台階共有多少種跳法</p><p>printf("請輸入台階總數n:");<br />scanf("%d", &n);<br />f[1] = 1; f[2] = 1; f[3] = 2;<br />for (k = 4; k <= n; k++)<br />f[k] = f[k - 1] + f[k - 3];<br />printf("跳%d級台階共有%d種跳法/n", n, f[n]);</p><p>return 0;<br />}
二、一般情況
1.問題深入
將問題的參數一般化,爬山台階有n級,一步有同種跳法,整數n與m種跳法各為多少級均為鍵盤輸入。
2.分級遞推演算法設計
設爬t級台階上山的不同爬法為f(t),設從鍵盤輸入一步跨多少級的m個整數分別為x(1),x(2),...,x(m)(約定x(1)<x(2)<...<x(m))。
因為一步能跨的台階數x(i)為鍵盤輸入,事前並不知道,因此不能在設計時簡單地確定f(x(1)),f(x(2)),...。
事實上,可以把初始條件放在分級遞推中求取,應用多種關係分組遞推完成遞推。
首先,探討f(t)的遞推關係:
當t<x(1)時,f(t)=0;f(x(1))=1(初始條件);
當x(1)<t<=x(2)時,第1級遞推:f(t)=f(t-x(1));
當x(2)<t<=x(3)時,第2級遞推:f(t)=f(t-x(1))+f(t-x(2));
……
一般地,當x(k)<t<=x(k+1),k=1,2,...,m-1,有第k級遞推:
f(t)=f(t-x(1))+f(t-x(2))+...+f(t-x(k))
當x(m)<t時,第m級遞推:
f(t)=f(t-x(1))+f(t-x(2))+...+f(t-x(m))
當t=x(2),或t=x(3),...,或t=x(m)時,按上遞推求f(t)外,還要加上1。道理很簡單,因此此時t本身即為一個一步到位的爬法。為此,應在以上遞推基礎上添加:
f(t)=f(t)+1 (t=x(2),x(3),...,x(m))
我們所示的目標為:
f(n)=f(n-x(1))+f(n-x(2))+...+f(n-x(m))
特殊處理
在遞推設計中我們可把台階數n記為數組元素x(m+1),這樣處理是巧妙的,可以按相同的遞推規律遞推計算,簡化演算法設計,最後一項f(x(m+1))即為所求f(n)。
最後輸出f(n)時必須把額外所添加的1減去。
2.代碼實現
#include <stdio.h></p><p>int main(void)<br />{<br />int i, j, k, m, n, x[10];<br />long f[200];</p><p>printf("請輸入總台階數:");<br />scanf("%d", &n);<br />printf("一次有幾種跳法:");<br />scanf("%d", &m);<br />printf("請從小到大輸入一步跳幾階/n");<br />for (i = 1; i <= m; i++)// 輸入m個一步跳級數<br />{<br />printf("第%d個一步可跳級數:", i);<br />scanf("%d", &x[i]);<br />}</p><p>// 確定初始條件<br />for (i = 1; i <= x[1] - 1; i++)<br />f[i] = 0;<br />x[m + 1] = n;<br />f[x[1]] = 1;</p><p>for (k = 1; k <= m; k++)<br />{<br />for (i = x[k] + 1; i <= x[k + 1]; i++)<br />{<br />f[i] = 0;<br />for (j = 1; j <= k; j++)// 按公式累加實現分級<br />f[i] = f[i] + f[i - x[j]];<br />if (i == x[k + 1])<br />f[i] = f[i] + 1;<br />}<br />}</p><p>printf("共有不同的跳法種數為:%d/n", f[n] - 1);</p><p>return 0;<br />}
選自《趣味C程式設計》