http://www.hankcs.com/program/m-n-recursive-division.html
有n个无区别的物品,将它们划分为不超过m组,求出划分方法数模M的余数。
限制条件:
1≤m≤n≤1000
2≤M≤10000
输入
n = 4
m = 3
M = 10000
输出:
4 (1 + 1 + 2 = 1 + 3 = 2 + 2 = 4)
这样的划分被称作n的m划分,特别的,m = n时被称作n的划分数。在此我们定义如下:
dp[i][j] = j 的 i 划分的总数
递推关系的难点在于不重复。我们采用一种标准将问题化为子问题,这个标准需要用到一种新的定义。我们定义n的m划分具体为一个集合{ai},{ai}满足∑mi=1 ai = n 。可以看出{ai}里一共有m个数,这m个数不一定大于0。
这个标准是:是否存在某个ai=0;这样可以将{ai}分为两种情况:
1、不存在某个ai=0
此时{ai}的个数等于{ai – 1}的个数,即 n – m 的 m 划分。理解起来并不难,集合里每个数都减去1,一共减了m个。
此时dp[i][j] = dp[i][j – i] 。
2、存在某个ai=0
此时{ai}的个数等于 n 的 m – 1 划分。可以这样思考,存在ai=0,说明划分一定不足m组,那么至少可以少分一组同时满足划分数相同。
此时dp[i][j] = dp[i – 1][j] 。
那么{ai}总的划分数就是这两种情况的综合,dp[i][j] = dp[i][j – i] + dp[i – 1][j]。
1 int n, m; 2 int dp[MAX_M + 1][MAX_N + 1]; 3 void solve() 4 { 5 dp[0][0] = 1; 6 for(int i = 1; i <= m; i++) 7 { 8 for(int j = 0; j <= n; j++) 9 { 10 if(j - i >= 0) 11 dp[i][j] = (dp[i - 1][j] + dp[i][j - 1]) % M; 12 else 13 dp[i][j] = dp[i - 1][j]; 14 } 15 } 16 }