请参考
贝尔数,以下是对这个问题的简要思考:
将一个包含n个元素的集合划分为m个非空集合,记为f(n,m)。
例如,一个包含3个元素的集合可以被划分为:
1)集合大小为1:{{1,2,3}, } <-- f(3,1)
2)集合大小为2:{{1,2},{3}}, {{1,3},{2}}, {{2,3},{1}} <-- f(3,2)
3)集合大小为3:{{1}, {2}, {3}} <-- f(3,3)
现在让我们来计算f(4,2):
有两种方法可以得到f(4,2):
A. 向f(3,1)添加一个集合,这将从{{1,2,3}, }转换为{{1,2,3}, {4}}
B. 将4添加到f(3,2)的任何一个集合中,这将从
{{1,2},{3}}, {{1,3},{2}}, {{2,3},{1}}
转换为
{{1,2,4},{3}}, {{1,2},{3,4}}
{{1,3,4},{2}}, {{1,3},{2,4}}
{{2,3,4},{1}}, {{2,3},{1,4}}
因此,f(4,2) = f(3,1) + f(3,2)*2
这导致f(n,m) = f(n-1,m-1) + f(n-1,m)*m
以下是获取所有集合划分的Java代码:
import java.util.ArrayList;
import java.util.List;
public class SetPartition {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
for(int i=1; i<=3; i++) {
list.add(i);
}
int cnt = 0;
for(int i=1; i<=list.size(); i++) {
List<List<List<Integer>>> ret = helper(list, i);
cnt += ret.size();
System.out.println(ret);
}
System.out.println("Number of partitions: " + cnt);
}
private static List<List<List<Integer>>> helper(List<Integer> ori, int m) {
List<List<List<Integer>>> ret = new ArrayList<>();
if(ori.size() < m || m < 1) return ret;
if(m == 1) {
List<List<Integer>> partition = new ArrayList<>();
partition.add(new ArrayList<>(ori));
ret.add(partition);
return ret;
}
List<List<List<Integer>>> prev1 = helper(ori.subList(0, ori.size() - 1), m);
for(int i=0; i<prev1.size(); i++) {
for(int j=0; j<prev1.get(i).size(); j++) {
List<List<Integer>> l = new ArrayList<>();
for(List<Integer> inner : prev1.get(i)) {
l.add(new ArrayList<>(inner));
}
l.get(j).add(ori.get(ori.size()-1));
ret.add(l);
}
}
List<Integer> set = new ArrayList<>();
set.add(ori.get(ori.size() - 1));
List<List<List<Integer>>> prev2 = helper(ori.subList(0, ori.size() - 1), m - 1);
for(int i=0; i<prev2.size(); i++) {
List<List<Integer>> l = new ArrayList<>(prev2.get(i));
l.add(set);
ret.add(l);
}
return ret;
}
}
结果如下:
[[[1, 2, 3]]]
[[[1, 3], [2]], [[1], [2, 3]], [[1, 2], [3]]]
[[[1], [2], [3]]]
分区数量:5