將求出的小規模的問題的解合併為乙個更大規模的問題的解,自底向上逐步求出原來問題的解。
分治法的設計思想是:將乙個難以直接解決的大問題,分割成一些規模較小的相同問題,以便各個擊破,分而治之。
遞迴的概念
直接或間接地呼叫自身的演算法稱為遞迴演算法。用函式自身給出定義的函式稱為遞迴函式。
由分治法產生的子問題往往是原問題的較小模式,這就為使用遞迴技術提供了方便。在這種情況下,反覆應用分治手段,可以使子問題與原問題型別一致而其規模卻不斷縮小,最終使子問題縮小到很容易直接求出其解。這自然導致遞迴過程的產生。
分治與遞迴像一對孿生兄弟,經常同時應用在演算法設計之中,並由此產生許多高效演算法。階乘函式可遞迴地定義為:
n! = 1 n = 0 (邊界條件)
n! = n(n-1)! n > 0 (遞迴方程邊界條件與遞迴方程是遞迴函式的二個要素,遞迴函式只有具備了這兩個要素,才能在有限次計算後得出結果。)
實現:
/**/#include
<
iostream
>
using
namespace
std;
//factorial implement by recursive
long
factorial_recursive(
long
n)//
factorial implement by loop
long
factorial_loop(
long
n)int
main()
return0;
}
無窮數列1,1,2,3
,5,8
,13,21
,34,55
,……,稱為fibonacci
數列。它可以遞迴地定義為:
f(n) = 1 n = 0 (邊界條件)
f(n) = 1 n = 1 (遞迴方程)
f(n) = f(n - 1) + f(n - 2) n > 2 (遞迴方程實現: /*)
*/#include
<
iostream
>
using
namespace
std;
//fibonacci implement by recursive
long
fibonacci_recursive(
long
n)//
fibonacci implement by loop
long
fibonacci_loop(
long
n)return
result;
}int
main()
例3 ackerman函式
當乙個函式及它的乙個變數是由函式自身定義時,稱這個函式是雙遞迴函式。
ackerman函式
a(n,
m)定義如下:
a(1,0) = 2
a(0,m) = 1 m >= 0
a(n,0) = n + 2 n >= 2
a(n,m) = a(a(n-1,m),m-1) n,m >= 1
前2例中的函式都可以找到相應的非遞迴方式定義:
本例中的ackerman
函式卻無法找到非遞迴的定義。
a(n,
m)的自變數
m的每乙個值都定義了乙個單變數函式:
m = 0時,
a(n,0)=n+2
m = 1時,
a(n,1)=a(a(n-1,1),0) = a(n-1,1)+2
,和 a(1,1)=2
故a(n,1)=2*n
m = 2時,
a(n,2) = a(a(n-1,2),1)=2a(n-1,2)
,和a(1,2)=a(a(0,2),1)=a(1,1)=2
,故a(n,2)= 2^n 。
m = 3時,類似的可以推出
m = 4時,
a(n,4)
的增長速度非常快,以至於沒有適當的數
學式子來表示這一函式。
實現:
/**/#include
<
iostream
>
using
namespace
std;
//ackerman implement
long
ackerman(
long
n,long
m)int
main()
例4
排列問題
設計乙個遞迴演算法生成n
個元素的全排列。
設r=是要進行排列的
n個元素,
ri=r-
。 集合x
中元素的全排列記為
perm(x)。
(ri)perm(x)表示在全排列
perm(x)
的每乙個排列前加上字首得到的排列。
r的全排列可歸納定義如下:
當n=1
時,perm(r)=(r)
,其中r
是集合r
中唯一的元素;
當n>1
時,perm(r)
由(r1)perm(r1)
,(r2)perm(r2)
,…,(rn)perm(rn)
構成。
/**/#include
<
iostream
>
#include
<
vector
>
#include
<
iterator
>
using
namespace
std;
/*使用遞迴實現
* 遞迴產生所有字首是list[0:k-1],
* 且字尾是list[k,m]的全排列的所有排列
* 呼叫演算法perm(list,0,n-1)則產生list[0:n-1]的全排列
*/template
<
class
t>
void
perm_recursion(t list,
intk,
intm)
else}}
//非遞迴實現(可參照stl next_permutation原始碼)
template
<
class
t>
void
perm_loop(t list,
intlen)}}
intmain()
;cout
<<
"permutation implement by recursion:
"<<
endl;
perm_recursion(list,0,
2);cout
<<
endl;
cout
<<
"permutation implement by loop:
"<<
endl;
perm_loop(list,3);
cout
<<
endl;
return0;
}
遞迴與分治策略
1 全排列問題 設r n 是要進行排列的n個元素。集合x中元素的全排列記為perm x 求r n 的全排列perm r n 用遞迴演算法求解 1 找出遞迴子結構性質 即原問題的解包含了子問題的解,且子問題的描述與原問題相同。這就可以用子問題的解來構造原問題的解。設r i r n 這是乙個子問題。設 ...
遞迴與分治策略
1.遞迴 直接或間接地呼叫自身的演算法稱為遞迴演算法。用函式自身給出定義的函式稱為遞迴函式。1 階乘函式 include using namespace std int main int factorial int n 2 fibonacci數列 include using namespace st...
分治策略與遞迴
先看 資料結構與演算法分析 中對分治策略的解釋 把問題分成兩個大致相等的子問題,然後再遞迴地對他們進行求解,這是 分 治 階段將兩個子問題的解合併到一起並可能再做些少量的附加工作,最後得到整個問題的解。由定義可以看出,分治需要進行兩步操作 分 將問題恰當的劃分為需要迭代處理的兩個子問題,治 將兩個子...