版权声明:本文为博主原创文章,若有错误之处望大家批评指正!转载需附上原文链接,谢谢! https://blog.csdn.net/summer_dew/article/details/83921730
问题
求含n个元素的集合的幂集
【注释】幂集:所有子集所组成的集合
【举例】
A={1,2,3}
ρ(A) = { {1,2,3}, {1,2}, {1,3}, {1}, {2,3}, {2}, {3}, ∅ }
思路
本问题可以用【分治法】来求解
从另一个角度分析问题:
幂集的每个元素时一个集合,它或是空集,或含集合A中的一个元素,或含集合A中两个元素,或等于集合A
【△】反之,从集合A的每个元素来看,它只有两个状态:
- 属于幂集的元素集
- 不属于幂集元素集
【结论】ρ(A)的元素的过程可看成是依次对集合A中元素进行“取”或“舍(弃)”的过程
做法
幂集元素在生成过程中的状态图:
可以用一棵二叉树,来表示过程中幂集元素的状态变化状况
- 【树中的根结点】幂集元素的初始状态,为空集
- 【叶子结点】它的终结状态
- 【第i层的分支结点】已对集合A中前i-1个元素进行了取/舍处理的当前状态
【结论】求幂集元素的过程即为先序遍历这棵状态树的过程
void PowerSet(int i,int n) {
// 求含n个元素的集合A的幂集ρ(A)。进入函数时已对A中前i-1个元素坐了取舍处理
// 现从第i个元素起进行取舍处理。若i>n,则求得幂集的一个元素,并输出之
// 初始调用:PowerSet(1,n);
if (i>n) 输出幂集的一个元素
else {
取第i个元素;PowerSet(i+1, n);
舍第i个元素;PowerSet(i+1, n);
}
}
拓展
图中状态变化树是一棵满二叉树:树中每个叶子结点的状态都是求解过程中可能出现的状态(即问题的解)。
【然而】很多问题用回溯和试探求解时,描述求解过程的状态树不是一棵满的多叉树
【非满多叉树】不是满的多叉树:当试探过程中出现的状态和问题所求解产生矛盾时,不再继续试探下去,这时出现的叶子结点不是问题的解的终结状态
此类问题的求解过程可看成是在约束条件下进行先序(根)遍历,并在遍历过程中剪去那些不满足条件的分支
【例子】四皇后问题
代码
void GetPowerSet(int i, List A, List &B) {
// 线性表A表示集合A,线性表B表示幂集ρ(A)的一个元素
// 局部量k为进入函数时表B的当前长度
// 第一次调用本函数时,B为空表,i=1
if (i>ListLength(A)) Output(B); //输出当前B值,即ρ(A)的一个元素
else {
GetElem(A, i, x); //得到A的第i个元素
k = ListLength(B);
ListInsert(B, k+1, x); //选中
GetPowerSet(i+1, A, B); //选中的,下一步
ListDelete(B, k+1, x); //不选中
GetPowerSet(i+1, A, B); //不选中的,下一步
}
}