持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第6天,点击查看活动详情
[NOIP2001 提高组] 数的划分
题目描述
将整数 分成 份,且每份不能为空,任意两个方案不相同(不考虑顺序)。
例如:下面三种分法被认为是相同的。
问有多少种不同的分法。
输入格式
输出格式
1 个整数,即不同的分法。
样例 #1
样例输入 #1
7 3
样例输出 #1
4
提示
四种分法为:
1,1,5;
1,2,4;
1,3,3;
2,2,3.
【题目来源】
NOIP 2001 提高组第二题
解题思路一:动态规划
DP的定义:
dp[i][j]:表示数字i分成j份的方案数
- 当第一个数为划分为
1时,1占用了第一个位置并且占用了总数中的1个数量 - 当第一个数不为
1时,可以表示为所有的位置上都加上一个1之后,再对于所有的位置用新的总数求方案数 - 综上,
dp方程如下:
#include<bits/stdc++.h>
using namespace std;
int main() {
int n, k;
cin >> n >> k;
vector<vector<int>> dp(n + 1, vector<int>(k + 1, 0));
for(int i = 1; i <= n; i++) {
dp[i][1] = 1;
}
for(int i = 2; i <= n; i++) {
for(int j = 2; j <= k; j++) {
if(i > j) dp[i][j] = dp[i - 1][j - 1] + dp[i - j][j];
else dp[i][j] = dp[i - 1][j - 1];
}
}
cout << dp[n][k] << endl;
return 0;
}
解题思路二:DFS
pre: 代表上一次划分的数字cur:当前划分的数字的和u:已经划分的份数
#include<bits/stdc++.h>
using namespace std;
int main() {
int n, k;
cin >> n >> k;
int ret = 0;
auto dfs = [&](auto&& self, int pre, int cur, int u) -> void {
if(u == k) {
if(cur == n) ret += 1;
return;
}
for(int i = pre; cur + i * (k - u) <= n; i++) {
self(self, i, cur + i, u + 1);
}
};
dfs(dfs, 1, 0, 0);
cout << ret << endl;
return 0;
}