【例题2】数的划分 ​题面 ​

题目描述

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

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

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

问有多少种不同的分法。

输入格式

两个整数, \(n\) 和 \(k\) 。

输出格式

输出不同的分法数。

样例

输入样例

7 3

输出样例

4

样例说明

四种分法为:1,1,5; 1,2,4; 1,3,3; 2,2,3.

数据范围与提示

对于 \(100\%\) 的数据,\(6<n\leq200,2\leq k\leq6\)。

分析 ​
  • 对于整数 \(n\) 的划分,我们可以从 \(1\) 开始,一步步考虑。

  • 首先,我们定一个数组 \(f[i][j]\) ,表示从 \(1\) 到 \(i\) 中,分成 \(j\) 份的分法有多少种。

  • 那么我们首先可以确定的是 当 \(i < j\) 的时候,\(f[i][j]=0\),因为我们明显无法将 \(i\) 个整数分成 \(j\) 份,且每份都不为空。

  • 当 \(i = j\) 的时候,\(f[i][j] = 1\),也就是 \(i\) 分成 \(j\) 份,且每份都为 \(1\)。

  • 当 \(i>j\) 的时候,\(f[i][j]=f[i-1][j-1]+f[i-j][j]\),

    • 对于前半种情况,是分成的 \(j\) 份中至少有一份为 \(1\),又因为题目说顺序不同认为是同种方案,所以,这种情况可以等同为 \(f[i - 1][j-1]\)。
    • 对于后半种情况,是分成的 \(j\) 份中没有一份为 \(1\),那么我们可以考虑将 \(j\) 份都减少 \(1\) 来算方案数,也就是 \(f[i-j][j]\),那么对于 \(f[i-j][j]\) 我们可以继续分下去,直到变成第一种情况或者是边界。
  • 因此,我们采用递推来解这一题。

Code ​
#include <bits/stdc++.h>
using namespace std;

int n, k;
long long f[250][10];

int main (void) {
    cin >> n >> k;
    for (int i = 1; i <= n; ++i) 
        for (int j = 1; j <= k; ++j) 
            if (i < j) f[i][j] = 0;
            else if (i == j) f[i][j] = 1;
            else f[i][j] = f[i - 1][j - 1] + f[i - j][j];
    cout << f[n][k];

    return 0;
}

Copyright ©2021 Juro