题目来源:
2016年中北大学新生赛
问题描述
郭姐最近很无聊,于是就开始分石头。郭姐有n颗石头,她要把石头分成m堆,每堆至少有一个石子,她想知道有多少种分法
输入描述
2个整数,n和m(m <= n <= 20)。
输出描述
一个整数,表示种数
样例
输入
7 3
输出
4
提示: (2,2,3)和(3,2,2)是同一种情况
思路:
记得以前做过一道题,n个物品给他划分成不超过m组,求有多少种方法。
dp[i][j]= j个物品划分成不超过i组的方法数
状态转移方程 dp[i][j]=dp[i-1][j]+dp[i][j-i];
解释一下这个方程怎么来的,j个物品分成不超过i组可以转移成,j个物品刚好分成i组 加上 j个物品分成不超过i-1组。
dp[i-1][j]就是 j个物品分成不超过i-1组。 dp[i][j-i]就是j个物品刚好分成i组,为什么呢?可以这样想,刚好分成i组,那么这i组每组至少有一个,先给每组分配一个,还剩下j-i个,把剩下的j-i个再分成不超过i组就是dp[i][j-i]
dp[0][0]=1;
可以求出dp[m][n] //n个物品分成不超过m组
而这道题算的是n个物品刚好分成m组。 那就是dp[m][n]-dp[m-1][n]了
下面给出代码:
#include<algorithm>
#include <cstdio>
using namespace std;
int dp[25][25];
int main(){
int n,m;
scanf("%d%d",&n,&m);
dp[0][0]=1;
for(int i=1;i<=m;i++){
for(int j=0;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]-dp[m-1][n]);
return 0;
}