时间限制:1.0s 内存限制:256.0MB
问题描述
将整数n分成k份,且每份不能为空,任意两份不能相同(不考虑顺序)。
例如:n=7,k=3,下面三种分法被认为是相同的。
1,1,5; 1,5,1; 5,1,1;
问有多少种不同的分法。
输入格式
n,k
输出格式
一个整数,即不同的分法
样例输入
7 3
样例输出
4 {四种分法为:1,1,5;1,2,4;1,3,3;2,2,3;}
数据规模和约定
6<n<=20,2<=k<=6
思路
将n划分为k个大于零的数的结果 = 划分结果中至少有一个1**+**划分结果中不存在1
论证1:划分结果中至少有一个1 = 将n-1分成k-1份的结果
理由:一定存在1,那么我就先划分出一个1,剩下的值无论怎么划分,最终结果中一定存在至少一个1
论证2:划分结果中不存在1 = 将n-k划分为k份的结果
理由:既然一定不存在1,则说明划分结果中的数一定都大于等于2,所以对于每一个数都减去1,那么剩下的结果一定是n-k划分成k份的结果
本文参考自 https://blog.csdn.net/dllgdxlxl/article/details/79438098
https://blog.csdn.net/qq_38786209/article/details/80111311
代码实现
//动规(递推)
//f[i][j]表示整数i划分为j份的分法
//至少存在一个1(存在):f[n-1][k-1] ;不包含1:f[n-k][k];
#include<iostream>
#include<cstring>
using namespace std;
main(){
int n,k;
cin >> n >> k;
int f[n+1][k+1];
memset(f,0,sizeof(f));
f[1][1]=1;
for(int i=2;i<=n;i++)
for(int j=1;j<=min(i,k);j++)
f[i][j]=f[i-1][j-1]+f[i-j][j];
cout << f[n][k] << endl;
return 0;
}
//动规(递归)
#include<iostream>
using namespace std;
int n,k;
int f(int a,int b){
if(a==0||b==0||b>a)
return 0;
if(a==b||b==1||a==b+1)
return 1;
return f(a-1,b-1)+f(a-b,b);
}
main(){
cin >> n >> k;
cout << f(n,k) << endl;
return 0;
}