上图为阿克曼函数的定义,根据函数解析式,我们可以很容易的写出递归式
def akm(m, n):
if m == 0:
return n + 1
elif m > 0 and n == 0:
return akm(m-1, 1)
elif m > 0 and n > 0:
return akm(m - 1, akm(m, n - 1))
m, n = map(int, input().split())
对于比较小的n值,m=1或2的情况,递归式是很好的,n值稍微大一些,我们也可以通过设置递归深度的方法求出答案
sys.setrecursionlimit(10000000)
但是,如果对于n值很大,或者m达到3,再去求解,递归深度就会大到我们无法忍受,这个时候,我们只能按照数学方法去求解这个问题
- 对于m=0,1,2,3我们进行分别讨论
m=0
这个时候显然有akm(0,n) = n+1
m=1
此时我们求解对象是akm(1,n),n=0时,根据函数,有akm(1,0)=akm(0,1)=2;如果n!=0,那么akm(1,n)=akm(0,akm(1,n-1)),注意此时我们可以带入函数得到akm(1,n)=akm(1,n-1)+1
这样我们就得到了后一项与前一项的递推关系,所以m=1这种情况阿克曼函数构成以2为首项,1为公差的等差数列,注意数列从0开始。这样我们求此数列的通项公式,可以得到akm(1,n)=n+2
m=2
此时我们的求解对象是akm(2,n),n=0时,根据函数,利用m=1的结论,有akm(2,0)=akm(1,1)=3,当n!=0时,利用m=1的结论,有akm(2,n)=akm(1,akm(2,n-1))=akm(2,n-1)+2,这样又构成了一个等差数列,同样求得akm(2,n)=2*n+3
m=3
此时我们的求解对象是akm(3,n),n=0时,根据函数,利用m=2的结论,有akm(3,0)=akm(2,1)=5,当n!=0时,利用m=1的结论,有akm(3,n)=akm(1,akm(3,n-1))=2akm(3,n-1)+3,求这个通项,利用高中的等比数列知识我们容易的想到可以两边同时加上3,得到akm(3,n)+3=2(akm(3,n-1)+3),这样就构成了一个等比数列,利用数列知识,求得akm(3,n)=2n+3-3
- 如果我们想求更大的m,答案已经非常巨大,想求得通项公式似乎也不是一件容易的事情,但我们可以根据上述方法进行递推的求解
- 所以就这道题可以看出对于计算机难以求解的问题,人类却可以容易的求解,这也正是数学的巨大力量