之前学习过递归与回溯,现在学习一下递归与分治。
分治的思想:对这k个子问题分别求解,如果子问题的规模仍然不够小,则再划分为多个规模更小的子问题,如此的递归进行下去,直到问题规模足够小,很容易求出其解为止。将求出的小规模问题的解,合并为一个更大规模的问题的解,自底向上逐步求出原来问题的解。
当一个函数及它的一个变量是由函数自身定义时,称这个函数是双递归函数。
Ackerman函数A(n,m)有两个独立的整型变量 m >=0 和 n >=0 ,其定义如下:
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
A(n,m)的自变量m的每一个值都定义了一个单变量函数:
m=0时,A(n,0) = n+2 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 n>=1
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)=2n n ≥1
m=3时,类似的可以推出 A(n,3)= 其中2的层数为n
m=4时,A(n,4)的增长速度非常快,以至于没有适当的数学式子来表示这一函数。
递归实现:
unsigned int akm(unsigned int n, unsigned int m)
{
if(n==1 && m==0)
return 2;
else if(n==0 && m>=0)
return 1;
else if(n>=2 && m==0)
return n+2;
else
return akm(akm(n-1, m), m-1);
}
非递归形式(这份代码并不是很严谨,因为计算过程中可能会溢出,所以最好用上一份代码):
//非递归形式: 不严谨,有可能溢出。
int Ackerman(int n, int m)
{
int i, j, akm[maxn][maxn];
memset(akm, 0, sizeof(akm)); //一段内存设为0,用于空间初始化
akm[1][0] = 2;
for(i = 0; i < maxn; i++)
akm[0][i] = 1;
for(i = 2; i < maxn; i++)
akm[i][0] = i + 2;
for(j = 1; j < maxn; j++)
for(i = 1; i < maxn; i++)
akm[i][j] = akm[akm[i-1][j]][j-1];
return akm[n][m];
}