n的m划分递推

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 }

 

posted @ 2018-03-23 19:44  陈辻柒  阅读(253)  评论(0编辑  收藏  举报