期末课程-算法设计与分析 整数划分问题

整数划分问题详解

整数划分问题,来源计算机算法设计与分析第二章的递归

问题描述

整数划分问题是指将正整数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

posted @ 2025-06-17 15:43  暮识深  阅读(117)  评论(0)    收藏  举报