首先考虑一个问题,假如我们在某个编译器上写出了这样的式子:(i++)(i++)(i++),假设i = 5,那么会有多少可能的结果?
显然,编译器对这种行为是未定义的,我们不知道i自增和乘法指令的执行顺序,可能的结果有5*5*5, 5*5*6, 5*5*7, 5*6*6, 5*6*7一共5种.那么问题来了,假如n个i++相乘,可能会有多少种情况???
对这个问题有多种解法,首先可以将其看作一个类似于排列组合的问题,假设乘法指令固定(n-1个),那么自增指令的可能位置右多少种?
注意到最后一个自增指令一定在最后一个乘法指令之后,实际上我们只需要考虑n-1个自增指令的位置,且注意到第i各乘法指令之前至多有i个自增指令,那么我们可以根据此写出递归方程,F[n][m] = F[n-1][m-1] + F[n-1][m],这实际上就是将问题分解成为两种简单一点的情况,当前要考虑的自增指令是否会在当前问题的第一个乘法指令前执行,如执行,则是F[n-1][m-1],否则 F[n-1][m];最后再考虑F[1][m],F[1][m] = 1+m,F[n][1] = n+1;从而可以写出递归的程序求解.
#recursion
def do_func(n,m):
if(n == 1):
return m+1
elif (m==1):
return n+1
else:
return do_func(n-1,m)+do_func(n-1,m-1)
def func(n):#this function is to make the user understand easier
return do_func(n-1,n-1)
但是要注意到一点,直接使用递归会导致内存以及时间开销都很大,因为很多状态在前面某次递归中我们已经求出来了,所以我们把它转换为动态规划:
注意以下创建list的办法!!
#dynamic plan
def do_func2(n,m):
F = [([0]*m) for i in range(n)]
for k in range(1,n):
F[1][k] = k+1
F[k][1] = k+1
for i in range(2,n):
for j in range(2,m):
F[i][j] = F[i-1][j]+ F[i-1][j-1]
return F[n-1][m-1]
def func2(n):
return do_func2(n,n)