题目描述:
将n个无区别的物品,划分成不超过m组,求出划分方法总数,输出总数模M的余数。
样例输入:
4 3 10000
将4划分为不超过3项:,有4种划分方法,所以输出
样例输出
4
算法
用动态规划,表示将划分成不超过组。
比如说dp[3][7]表示将7划分成不超过3组,划分方法如下:
一共有8种划分方法,现在观察上述8种划分,既然是划分成不超过3项,干脆给未满3项的划分补0,使之变成3项。这样一来,上述8种划分方式就被分为不含0的划分和含0的划分。
对于所有将4划分成不超过3项:1+1+2、2+2+0、1+3+0、4+0+0(补0保证每种划分都是3项),将每种划分中每一项都加1:2+2+3、2+2+1、2+4+1、5+1+1,发现这些都是将7划分成不超过3项的结果中,不含0的划分。
反之,7划分成不超过3项的结果中,所有不含0的划分,都能将每一项减1变成将4划分为不超过3项。
所以,中不含0的划分就等于。
对于所有将7划分为不超过2项的划分结果,加个0便成为了将7划分为不超过3项的结果。
对于所有将7划分为不超过3项的划分结果中,含0的划分,去掉一个0便得到了将7划分为不超过2项的划分结果。
所以,中含0的划分就等于。
综上所述,递推关系为:
初始值为:
没有任何非零数是0个数的和,数字0无论分成几项之和都只有一种方式。
代码
#include<stdio.h>
#define maxn 1005
int n, m, M;
int dp[maxn][maxn];
int main(){
while(scanf("%d %d", &n, &m)==2){
for(int i = 0;i <= m;i++){
dp[i][0] = 1;
}
for(int j = 1;j <= n;j++){
dp[0][j] = 0;
}
scanf("%d", &M);
for(int i = 1;i <= m;i++){
for(int j = 1;j <= n;j++){
if(j>=i){
dp[i][j] = dp[i-1][j] + dp[i][j-i];
}
else{
dp[i][j] = dp[i-1][j];
}
}
}
printf("%d\n", dp[m][n]%M);
}
return 0;
}