算法设计与分析 SCAU19180 集合划分问题

  • Post author:
  • Post category:其他




19180 集合划分问题

时间限制:1000MS 代码长度限制:10KB

提交次数:0 通过次数:0

在这里插入图片描述

题型: 编程题 语言: G++;GCC;VC;JAVA



Description

教材课后习题2-8

n个元素的集合{1,2,…,n}可以划分若干个非空子集。例如,当n=4时,集合{1,2,3,4}可以划分为15个不同的非空子集如下:

{

{1},{2},{3},{4}},

{

{1,2},{3},{4}},

{

{1,3},{2},{4}},

{

{1,4},{2},{3}},

{

{2,3},{1},{4}},

{

{2,4},{1},{3}},

{

{3,4},{1},{2}},

{

{1,2},{3,4}},

{

{1,3},{2,4}},

{

{1,4},{2,3}},

{

{1,2,3},{4}},

{

{1,2,4},{3}},

{

{1,3,4},{2}},

{

{2,3,4},{1}},

{

{1,2,3,4}}

给定正整数n(1<=n<=20),计算出n个元素的集合{1,2,…,n} 可以化为多少个由m个不同的非空子集组成的集合。



输入格式

两个整数n和m。



输出格式

集合划分的数量。

注意此类问题数据较大,需要使用long long 类型。



输入样例

4 3



输出样例

6



解题思路



递归



找规律

递归思路:以最大数n为例

  1. n

    独立作为一个子集

    ,问题就演变为 n – 1 个数分为 m – 1 个集合。即:如果现在是将4个元素划分为3个集合,如果加入第四个数时要求为独立一个子集,那在这基础上,结果加上个数为3个元素划分为2个集合的数量。
  2. n 和其他数字在一起构成子集,那么先将 n – 1 个数字分为 m 个集合,再将 n 插入到这 m 个集合中的某个集合中去,因此此时会有 m 种插入方案。


举例

以集合元素个数为4为例,我们来看应该怎么求解集合划分问题。因为我们采用的是分治策略,因此,我们先看集合元素个数为3的集合的划分

考虑3个元素的集合,可划分为

  1. 1个子集的集合:{

    {1,2,3}}
  2. 2个子集的集合:{

    {1,2},{3}},{

    {1,3},{2}},{

    {2,3},{1}}
  3. 3个子集的集合:{

    {1},{2},{3}}

因此 F(3, 1) = 1; F(3, 2) = 3; F(3, 3) = 1;

如果我们要求4个元素的集合划分为2个子集的集合的个数F(4,2),求解过程如下:

  • 如果这第4个元素不是独立子集,因此在2个子集的集合中加入4,加入4的方式如下:

    {

    {1,2,4},{3}},{

    {1,2},{3,4}},

    {

    {1,3,4},{2}},{

    {1,3},{2,4}},

    {

    {2,3,4},{1}},{

    {2,3},{1,4}}

即如果有 m 个子集,那么该情况的个数为 m * F(n – 1, m)

  • 如果这第4个元素作为独立子集,只有一种方式

    {

    {1,2,3},{4}}

即在 F(n – 1, m – 1) * 1


所以:F(4, 2)= 2 * F(3, 2)+ F(3, 1)

由以上的演示可以得出集合划分的公式如下:

在这里插入图片描述

此式中n为元素个数,m为子集个数。



递归终止条件
  1. 可划分为的集合数为1时,即不能再少了;
  2. 当 n == m,即元素和集合个数相等时,比如6个元素划分为4个,只能递归至4个元素划分为4个集合,而不能继续递归成3个元素划分为4个集合了(此时会出现空集合,而题目要保证每个集合至少一个元素)。



算法思路

更多注释可查看下方的完整代码中,有助于理解



代码如下
#include <iostream>

using namespace std;
/*
20 10
5917584964655
*/

long long f(int n,int m)
{
    // 递归结束条件,n和m相等,即此时每个集合只有一个元素,因为比如4个元素最多只能划分为4个集合,或只划分为1个集合
    if(n == m || m == 1) {
        return 1;
    } else {
        return f(n - 1, m - 1) + m * f(n - 1, m);
    }

}

int main()
{
    int n, m;
    cin >> n >> m;

    cout << f(n, m) << endl;

    return 0;
}



最后

对我感兴趣的小伙伴可查看以下链接



版权声明:本文为weixin_53893220原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。