划分数 挑战上的题
***************************************************************************************
注意是不超过
1、定义dp[i][j]=j的i的划分总数 j的i划分表示的意义为 j固定,i可以取到1-i。
2、递推公式 dp[i][j]=dp[i][j-i]+dp[i-1][j];
3、分类讨论:
1.j >= i时,dp[i][j] = dp[i-1][j] ( j的i-1划分,相当于当前位取0的全部情况 ) + dp[i][j-i](当前位不取0,先把每一个置为1,再将剩下的j-i分下去);
2.j < i时,dp[i][j] = dp[i-1][j]; 当前位只能取0。
例题:
郭姐最近很无聊,于是就开始分石头。郭姐有n颗石头,她要把石头分成m堆,每堆至少有一个石子,她想知道有多少种分法
输入描述
-
2个整数,n和m(m <= n <= 20)。
输出描述
-
一个整数,表示种数
样例输入 7 3 样例输出 4
来源 2016年中北大学新生赛
提示 由于石头都是一样的,若仅仅只是顺序不同,那还是同一种分法,比如把7分成3堆,(1,1,5)和(1,5,1)是同一种
注意是刚好m堆,每堆至少一个石子
上述提到的公式是适用于不超过m即空堆是小于m的数即可 所以注意最后答案是(看代码)
#include<cstdio>
#include<cstring>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<stdlib.h>
using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=1000000;
int dp[50][50];
int main(){
int n,m;
cin>>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][j-i]+dp[i-1][j];
}else
dp[i][j]=dp[i-1][j];
}
}
int ans=dp[m][n]-dp[m-1][n];//注意
cout<<ans<<endl;
return 0;
}
牛客 放苹果 一样的题https://www.nowcoder.com/questionTerminal/bfd8234bb5e84be0b493656e390bdebf
不过是不超过M堆的情况;
#include<algorithm>
#include<iostream>
#include<stdlib.h>
using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=1000000;
int dp[50][50];
int main(){
int n,m;
cin>>m>>n;
dp[0][0]=1;
for(int i=1;i<=n;i++){
for(int j=0;j<=m;j++){
if(j>=i)
dp[i][j]=dp[i][j-i]+dp[i-1][j];
else
dp[i][j]=dp[i-1][j];
}
}
int ans=dp[n][m];
cout<<ans<<endl;
return 0;
}
递归也可以写
牛客该题下讨论有详解,感兴趣可以去学一下