将整数n分成k份,且每份不能为空,任意两种分法不能相同(不考虑顺序)。
例如:n=7,k=3,下面三种分法被认为是相同的:
1,1,5; 1,5,1; 5,1,1。
问有多少种不同的分法。
输入:n,k(6
输出:一个整数,即不同的分法。
输入输出样例
输入:
7 3
输出:
4
典型的划分DP问题。http://codevs.cn/wiki/solution/?problem_id=1039
//dp[i][j]=dp[i][j-i]+dp[i-1][j-1];
//假设这所有前i份最底层的1都不去动它,那么
//dp[i][j-i]是指第i份个数大于1的时候的方法数
//dp[i-1][j-1]是指第i份个数等于1的时候的方法数
#include
using namespace std;
int n,m,dp[10][205];
int main(){
scanf("%d %d",&n,&m);
dp[0][0]=1;
for(int i=1;i<=m;i++){
for(int j=i;j<=n;j++){
dp[i][j]=dp[i][j-i]+dp[i-1][j-1];
}
}
printf("%d\n",dp[m][n]);
return 0;
}
个人认为这种写法理解起来会比较简单:
#include
using namespace std;
int n,m,dp[10][205];
int main(){
scanf("%d %d",&n,&m);
dp[1][1]=1;
for(int i=1;i<=m;++i){
for(int j=i;j<=n;++j){
if(j+i<=n)
dp[i][j+i]+=dp[i][j]; //所有点上面再铺一层
dp[i+1][j+1]+=dp[i][j]; //再增加一份,个数是1
}
}
printf("%d\n",dp[m][n]);
return 0;
}
不得不感慨编程之美乃造物者之无尽藏也。。。
一次掷n个骰子,每个骰子有p个面,问有多少种情况?
2个骰子,3个面,1,1,2和2,1,1是一种情况
对于这种情形 我们一般进行排序处理 把所有情况所对应的数从小到大排序
a1<=a2<=a3<=...<=an
比如1,1,2和2,1,1就相当于1,1,2了
再比如 3,1,2 2,3,1 都相当于1,2,3
这样每种情况都与一个序列一一对应不是吗?
下面我们求排列数
n个骰子,每个骰子有p个面 那么我们只要知道这p个面 每个面出现了多少次,依据上述的排序规则 这个序列就确定了
然后就转化成了一个方程
x1+x2+x3+...xp=n 有多少组非负整数解
(xi代表第i个面出现了多少次)
对于这个方程 我们令ai=xi+1
则x1+x2+x3+...xp=n的非负数解与方程 a1+a2+a3+...ap=n+p的正数解一一对应
a1+a2+a3+...ap=n+p 这个方程的正数有多少组解呢? 答案是C(n+p-1,p-1)种
因为可以看成是有n+p个1 然后中间插入p-1个板子 隔板法求得方程的解数
所以一次掷n个骰子,每个骰子有p个面 有C(n+p-1,p-1)种情况.
附动态规划方程
dp[i][j] 前i个筛子 第i个筛子面值为j的方法数目
dp[1][j]=1 (1<=j<=p)
dp[i][j]=Sigma(dp[ i-1
][k]) i>1 1<=k<=j