题目描述
将整数 n分成 k 份,且每份不能为空,任意两个方案不相同(不考虑顺序)。
例如:n=7,k=3,下面三种分法被认为是相同的。
1,1,5;
1,5,1;
5,1,1.
问有多少种不同的分法。
输入格式
n,k(6<n<=200,2 <=k<=6)
输出格式
1 个整数,即不同的分法。
输入输出样例
提示
四种分法为:
1,1,5;
1,2,4;
1,3,3;
2,2,3.
代码实现
思路一:深度优先搜索DFS(递归)+剪枝
剪枝的思路:为了避免分法重复,我们一般按照“不降原则”进行划分,也就是a1<=a2<=a3……
#include <bits/stdc++.h>
using namespace std;
int n, k;
int num = 0; //记录满足要求的划分数
void dfs(int c, int sum, int p) { //c:计数,sum:当前和,p:遍历的起始位置
if (c == k) {
if (sum == n)
num++;
return ;
}
for (int i = p; sum + i * (k - c) <= n; i++) { //为了避免重复,划分按照“不降原则”a1<=a2<=a3……
dfs(c + 1, sum + i, i);
}
}
int main() {
cin >> n >> k;
dfs(0, 0, 1);
cout << num << endl;
return 0;
}
思路二:动态规划 DP(递推)
"把值为n的数划分为k个部分"这个问题等价于"将n个小球放入到k个盒子当中,不考虑盒子的区别"。我们可以将这个问题分为两种情况讨论:
(1)至少有一个盒子里面只有一个小球
(2)不存在盒子里面只有一个小球的情况
为什么要按照上述情况划分,因为好表示,容易写出递推公式。
注意:盒子不为空,必须要有小球;n个小球必须全部放入k个盒子中。
设d[i][j]表示将i个小球放入j个盒子当中,则有:
(1)中情况等价于:将n-1个求放入k-1个盒子中d[n-1][k-1]
(2)中情况等价于:将n-k个球放入k个盒子中d[n-k][k]
#include <bits/stdc++.h>
using namespace std;
int main() {
int n, k;
cin >> n >> k;
int d[210][10];
for (int i = 1; i <= n; i++) {
d[i][1] = 1;
}
for (int i = 1; i <= n; i++) {
for (int j = 2; j <= k; j++) {
if (i >= j) {
d[i][j] = d[i - 1][j - 1] + d[i - j][j];
}
}
}
cout << d[n][k] << endl;
return 0;
}