算法设计与分析: 2-8 集合划分问题

算法设计与分析: 2-8 集合划分问题算法设计与分析: 2-8 集合划分问题

package cn.htu.test;
/**
 * 分析:
 * 设n个元素的集合可以划分为S(n,m)个不同的由m个非空子集组成的集合。
S(n,m)的两种情况:
一种是独自组成一个集合,另一种是和别的元素混在一起。
对於第一种情况,等价于把前n-1个元素分成m-1份,然后n号元素单独放。
对於第二种情况,等价于把前n-1个元素分成m份,然后把n号元素放入这m个集合中的一个(有m种放法)
推出:
S(n,m) = S(n-1,m-1) + m * S(n-1,m)
得出这个式子至关重要,而我们所要求的就是{{  },{  },{  }},有几个这样的外层大括号
 */
import java.util.Scanner;

public class JiHeHuaFen {

    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);

        while (true){
            long sum = 0;//总数sum用来装有多少个这样的集合即外层大括号

            System.out.println("Input n: ");//n就是集合的元素数
            //当然,这里要注意的是整道题的非空子集的概念和数学平常遇到的非空子集的概念是不同的
            int n = input.nextInt();

            System.out.println("Input m: ");
            int m = input.nextInt();

            sum = S(n, m);

            System.out.println("There are "+sum+" different sets!");
            System.out.println("----------------------------------------");
        }
    }

    //递归函数
    private static long S(int n, int m){
        if((n < m) || (m == 0))
            return 0;//如果n不够m分或者不用分(即m==0),则得到的划分外层的大括号个数为0
        if((m == n) || (m == 1))
            return 1;
        //例如如果4个元素划分为m=4,即{{},{},{},{}}的话得到只有这一种结果
        //再比如4个元素划分为m=1,即{{}},得到也只有一种结果,这就是集合划分的"内满"和"外满"

        return m*S(n-1, m) + S(n-1, m-1);
        //以上两种特殊情况都不是的话就是正常的两种情况了,前面的分析已经说过了
    }
}