期末课程-算法设计与分析 整数划分问题
整数划分问题详解
整数划分问题,来源计算机算法设计与分析第二章的递归
问题描述
整数划分问题是指将正整数n表示成一系列正整数之和。例如,正整数6有如下11种不同的划分,所以P(6)=11:
- 6
- 5+1
- 4+2,4+1+1
- 3+3,3+2+1,3+1+1+1
- 2+2+2,2+2+1+1,2+1+1+1+1
- 1+1+1+1+1+1
我们的目标是求出正整数n的不同划分个数P(n)。注意这是题目要求,对于递归问题要将其变为一个f(n,m)的函数问题
算法分析
递归思路
个人认为递归可以说是动态规划dp的前置,所以这个dp也是在书中放在了第三章
定义一个二维数组dp,其中dp[i][j]表示将正整数i划分成最大加数不超过j的划分个数。故有以下递推关系:
- 1、i等于1或者j等于1,则
dp[i][j] = 1。要划分的是1或最大加数是1,只有一种方式。 - 2、i < j,则
dp[i][j] = dp[i][i]。在这种情况下,j相当于超出了范围。 - 3、i == j,则
dp[i][j] = dp[i][j-1] + 1。即可以将i划分为至少一个j的项和剩下的部分。 - 4、i > j > 1,则
dp[i][j] = dp[i][j-1] + dp[i-j][j]。这里,dp[i][j-1]表示不包含j的划分方式数,dp[i-j][j]表示包含至少一个j的划分方式数。
正整数n的划分数P(n)就是dp[n][n]。
伪代码实现
以下是该算法的伪代码表示:
输入正整数n
创建一个(n+1)×(n+1)的二维数组dp,并初始化为0
for i从1到n:
for j从1到n:
if i == 1 或 j == 1:
dp[i][j] = 1
else if i < j:
dp[i][j] = dp[i][i]
else if i == j:
dp[i][j] = dp[i][j-1] + 1
else:
dp[i][j] = dp[i][j-1] + dp[i-j][j]
输出P(n) = dp[n][n]
思考
在没有进一步的验证情况下,我发现i<j的情况是否可以和i=j合并?也就是说i<j时,dp[i][j] = dp[i][i]= dp[i][j-1] + 1,可以减少一个分支的判断,即i<=j有dp[i][j] = dp[i][j-1] + 1?不合并的情况倒是可以通过记忆P(n)来直接出结果,不过那也不是程序记得的
举例来说,dp[7][10]=dp[7][7]=dp[7][6]+1=14+1=15(=P(7))
dp[7][6]=dp[7][5]+dp[1][6]=dp[7][5]+1
=dp[7][4]+dp[2][5]+1 #这里又可以用一次上面的式子
=dp[7][4]+P(2)+1=dp[7][4]+dp[2][1]+1+1
=dp[7][3]+dp[4][3]+3=……
=14

浙公网安备 33010602011771号