[回溯法] 1 求n个元素的集合的幂集

版权声明:本文为博主原创文章,若有错误之处望大家批评指正!转载需附上原文链接,谢谢! 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的每个元素来看,它只有两个状态:

  1. 属于幂集的元素集
  2. 不属于幂集元素集

【结论】ρ(A)的元素的过程可看成是依次对集合A中元素进行“取”或“舍(弃)”的过程

做法

幂集元素在生成过程中的状态图:
幂集元素在生成过程中的状态图

可以用一棵二叉树,来表示过程中幂集元素的状态变化状况

  1. 【树中的根结点】幂集元素的初始状态,为空集
  2. 【叶子结点】它的终结状态
  3. 【第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); //不选中的,下一步
	}
}

猜你喜欢

转载自blog.csdn.net/summer_dew/article/details/83921730