求解ackermann函数
{n+1; m=0,n>0
A(m,n)= {A(m-1,1); n=0,m>0
{A(m-1,A(m,n-1)) n>0,m>0
求救动态规划算法!
最简单的方法,用动态规划的备忘录法
即使用一个二维数祖A[1..m,1..n]记录所有的ackermann函数值
初始的时候全部填充-1,表示尚未计算过
然后直接用递归函数计算ackermann函数
在递归计算之前,现判断数组A中该函数值是否以被计算过,如果计算过了则直接从数组A中取出结果,不要再做重复计算;如果没有计算过,则递归计算。
大致的算法过程如下:
Ackermann(m, n)
1. if A[m,n] >= 0
2. then return A[m, n];
3. else if m = 0 and n > 0
4. then A[m,n] <- n + 1;
5. else if n = 0 and m > 0
6. then A[m,n] <- Ackermann(m-1, 1);
7. else if n > 0 and m > 0
8. then A[m,n] <- Ackermann(m-1, Ackermann(m, n-1));
9. return A[m, n];
Ackermann函数A(m,n)可递归定义如下:
当m=0时,A(m,
n)=n+1
当m>0,n=0时,A(m,n)=A(m-1,1)
当m>0,n>0时,A(m,n)=A(m-1,A(m,n-1))
试设计一个计算A(m,n)的动态规划算法,该算法只占用O(m)空间。
用两个一维数组,ind[i]和val[i],使得当ind[i]等于t时,val[i]=A(i,ind[i])。
i ind[i] val[i]
0 0 1
1 -1 0
2 -1 0
……
初始时,令ind[0]=0,val[0]=1,ind[i]=-1(i>0),val[i]=0(i>0)。
1当m=0时,A(m,n)=n+1。
任给一个t,当ind[0]=t时,能够求出val[0]的值,val[0]等于ind[0]。
2当n=0,m>0时,A(m,n)=n+1。
能够求出当ind[i]=0时,val[i]的值,此时val[i]等于当ind[i-1]等于1时val[i-1]的值。
3当m>0,n>0时,A(m,n)=A(m-1,A(m,n-1))。
当ind[i]=t,val[i]=s时,要求当ind[i]’=t+1时val[i]’的值。
Val[i]’=A(i,ind[i]’)=A(i-1,A(i,ind[i]’-1)=A(i-1,A(i,ind[i]))=A(i-1,val[i])
所以,当ind[i-1]=val[i]时,能够求出当ind[i]’=k+1时,val[i]’=val[i-1]。
#include <stdio.h>
int ack(int& m,int& n)
{
int i,j;
int *val=new int[m+1];
int *ind=new int[m+1];
for(i=1;i<=m;i++)
{
ind[i]=-1;
val[i]=-1;
}
ind[0]=0;
val[0]=1;
while(ind[m]<n)
{
val[0]++;
ind[0]++;
printf(“%d “,val[0]);
for(j=1;j<=m;j++)
{
if(1==ind[j-1])
{
val[j]=val[j-1];
ind[j]=0;
}
if(val[j]!=ind[j-1])
break;
ind[j]++;
val[j]=val[j-1];
}
}
printf(“/n”);
printf(” i ind[i] val[i]/n”);
for(i=0;i<=m;i++)
printf(“%5d %6d %6d/n”,i,ind[i],val[i]);
return val[m];
}
void main()
{
int m,n,ak;
printf(“Ackmann(m,n)/nPlease enter m:”);
scanf(“%d”,&m);
printf(“Please enter n:”);
scanf(“%d”,&n);
ak=ack(m,n);
printf(“the Ackmann(%d,%d) is %d/n”,m,n,ak);
}