【动态规划 & DFS】 洛谷P1025 数的划分

156 阅读1分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第6天,点击查看活动详情

[NOIP2001 提高组] 数的划分

题目描述

将整数 nn 分成 kk 份,且每份不能为空,任意两个方案不相同(不考虑顺序)。

例如:n=7k=3n=7,k=3,下面三种分法被认为是相同的。

1,1,5;1,5,1;5,1,1.1,1,5; 1,5,1; 5,1,1.

问有多少种不同的分法。

输入格式

n,k6<n2002k6n,k (6<n \le 200,2 \le k \le 6)

输出格式

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方程如下:

dp[i][j]=dp[i1][j1]+f[ij][j]dp[i][j] = dp[i-1][j-1] + f[i - j][j]

 #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;
 }