1. 从"放苹果"到整数划分:问题本质的揭示
第一次遇到"放苹果"这道题是在大学算法课上,当时觉得这不过是个简单的排列组合问题。直到后来准备算法竞赛时,才发现它背后隐藏着整数划分这一经典问题的通用解法。让我们从一个具体例子开始:把7个苹果放进3个盘子有多少种方法?手工枚举的话,你会得到(5,1,1)、(4,2,1)、(3,3,1)、(3,2,2)等共8种方案。
这个问题之所以特殊,在于两个关键约束:苹果不可区分(所有苹果相同)和盘子不可区分(顺序不重要)。这正好对应着数学中的整数划分问题——将一个正整数表示为若干正整数之和的不同方式。在算法领域,这类问题通常有两种解法:自底向上的递推(动态规划)和自顶向下的递归。
我更喜欢把这个问题想象成给小朋友分糖果。假设你有7颗相同的糖果要分给3个小朋友,有的小朋友可能一颗都拿不到(允许空盘子),而且分配顺序不重要((5,1,1)和(1,5,1)算同一种)。这种生活化的类比能帮助初学者快速抓住问题本质。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 递推解法:动态规划的思维艺术
2.1 状态定义与初始化
动态规划解法的核心在于状态定义。我们定义dp[m][n]表示m个苹果放入n个盘子的方法数。初始化时有三个边界条件:
- dp[0][n] = 1:没有苹果时只有一种分法(所有盘子为空)
- dp[m][1] = 1:只有一个盘子时只能全部放入
- dp[1][n] = 1:只有一个苹果时无论多少盘子都只有一种放法
cpp复制int dp[11][11] = {0}; // 题目限制M,N≤10
for(int i=0; i<=10; ++i) {
dp[0][i] = 1;
dp[1][i] = 1;
dp[i][1] = 1;
}
2.2 状态转移方程推导
递推关系需要考虑两种情况,这也是动态规划最精妙的部分:
- 盘子比苹果多(n > m):必然有n-m个空盘子,这些空盘子不影响结果,所以等价于dp[m][m]
- 苹果不少于盘子(m ≥ n):可以分为两种情况
- 至少有一个盘子为空:方法数等于dp[m][n-1]
- 所有盘子都有苹果:先在每个盘子放1个苹果,剩下m-n个苹果继续分配,方法数等于dp
