遞迴和遞推,遞迴遞推
遞迴的概念
一個函數、過程、概念或資料結構,如果在其定義或說明內部直接或間接地出現有其本身的引用,或者是為了描述問題的某一狀態,必須用到它的上一狀態,而描述上一狀態,又必須用到它的上一狀態……這種用自己來定義的方法,稱之為遞迴或者遞迴定義。
在程式設計中,過程或函數直接或者間接調用自己,就稱為遞迴調用
遞迴過程實際上藉助於一個遞迴工作棧來實現的。
首先問題向一個方向一步一步分解,既問題規模逐漸降低,這樣,問題向一極推進的過程稱之為遞迴過程;
然後這些問題又按後提出先解決的順序依次得到解決,最後得到原問題的解。這樣,在子問題得到逐一解決的基礎上,最後回到原問題的解的變化過程,稱之為迴歸過程。
遞迴定義的要素
1、遞迴邊界或終止條件。
2、遞迴定義,使問題向邊界條件轉化的規則。
var
n:integer;
function fibonacci(x:integer):integer;
begin
if (x=0) or (x=1) then exit(1);
exit(fibonacci(x-1)+fibonacci(x-2));
end;
begin
readln(n);
writeln(fibonacci(n));
end.
集合的劃分
設s是一個具有n個元素的集合,s={a1,a2,……,an},現將s劃分成K個滿足下列條件的子集合s1,s2,……,sk ,且滿足:
1.si≠φ
2.si∩sj=φ (1≤i,j≤k i≠j)
3.s1∪s2∪s3∪…∪sk=s
則稱s1,s2,……,sk是集合s的一個劃分。它相當於把s集合中的n個元素a1 ,a2,……,an 放入k個(0<k≤n<30)無標號的盒子中,使得沒有一個盒子為空白。請你確定n個元素a1 ,a2 ,……,an 放入k個無標號盒子中去的劃分數s(n,k)。
先舉個例子,設S={1,2,3,4},k=3,不難得出s有6種不同的劃分方案,即劃分數s(4,3)=6,具體方案為:
{1,2}∪{3}∪{4}
{1,3}∪{2}∪{4}
{1,4}∪{2}∪{3}
{2,3}∪{1}∪{4}
{2,4}∪{1}∪{3}
{3,4}∪{1}∪{2}
考慮一般情況,對於任意的含有n個元素a1 ,a2,……,an的集合s,放入k個無標號的盒子中去,劃分數為s(n,k),我們很難憑直覺和經驗計算劃分數和枚舉劃分的所有方案,必須歸納出問題的本質。
下面考慮對任一個元素an,則必然出現以下兩種情況:
1、{an}是k個子集中的一個,於是我們只要把a1,a2,……,an-1 劃分為k-1子集,便解決了本題,這種情況下的劃分數共有s(n-1,k-1)個;
2、{an}不是k個子集中的一個,則an必與其它的元素構成一個子集。則問題相當於先把a1,a2,……,an-1 劃分成k個子集,這種情況下劃分數共有s(n-1,k)個;然後再把元素an加入到k個子集中的任一個中去,共有k種加入方式,這樣對於an的每一種加入方式,都可以使集合劃分為k個子集,因此根據乘法原理,劃分數共有k*s(n-1,k)個。
綜合上述兩種情況,應用加法原理,得出n個元素的集合{a1,a2,……,an}劃分為k個子集的劃分數為以下遞迴公式:
s(n,k)=s(n-1,k-1)+k*s(n-1,k) (n>k,k>0)。
確定s(n,k)的邊界條件
首先不能把n個元素不放進任何一個集合中去,即k=0時,s(n,k)=0;
也不可能在不允許空盒的情況下把n個元素放進多於n的k個集合中去,即k>n時,s(n,k)=0;
再者,把n個元素放進一個集合或把n個元素放進n個集合,方案數顯然都是1,即k=1或k=n時,s(n,k)=1。
可以得出劃分數s(n,k)的遞迴關係式為:
s(n,k)=s(n-1,k-1)+k*s(n-1,k) (n>k,k>0)
s(n,k)=0 (n<k)或(k=0)
s(n,k)=1 (k=1)或(k=n)
遞迴與非遞迴的轉化
在遞迴調用的過程中,由於要保留每次調用時的參數和局部變數,而且要經過逐層調用和逐層返回兩大過程,程式對於時間和儲存空間的耗費可以說是巨大的。因此,在一個問題對於時空要求較高的情況下,有時不得不將遞迴方法轉化成非遞迴方法,這一過程,常常稱之為消除遞迴。消除遞迴的過程,其本質上就是要求類比複雜的遞迴工作棧的變化過程,雖然遞迴與非遞迴在形式上大多能夠相互轉化,但是,非遞迴的編程難度要遠遠高於遞迴的方法
遞推
在問題類型中,每個資料項目都和它前面的若干個資料項目(或後面的若干個資料項目)有一定的關聯,這種關聯一般是通過一個遞推關係式來表示的。求解問題時就從初始的一個或若干個資料項目出發,通過遞推關係式逐步推進,從而得到最終結果。這種求解法就叫遞推法
var
a:array[0..100] of longint;
i:integer;
begin
readln(n);
a[0]:=1;
a[1]:=1;
for i:=2 to n do
a[i]:=a[i-1]+a[i-2];
writeln(a[n]);
end.
演算法架構
1、確定求解初始條件
2、求出遞推公式
3、從邊界出發進行順推或反向推算
4、輸出結果
具體詳見:
http://download.csdn.net/download/boyxiejunboy/8913331
http://download.csdn.net/download/boyxiejunboy/8913339
http://download.csdn.net/download/boyxiejunboy/8913343
(不用積分下載哦)
著作權聲明:本文為博主原創文章,未經博主允許不得轉載。