子集枚举问题求解-Prolog

 
由n个元素构成的集合有2^n个子集,例如,集合{1,2,3}的子集有:
空集:1个      {}
一元子集:3个      {1},{2},{3}
二元子集:3个      {1,2},{1,3},{2,3}
三元子集:1个      {1,2,3}
共8个子集。
下面我们考虑一个集合S的所有子集的枚举方法。
首先,空集仅有一个子集,即空集本身。
其次,当S非空集时,我们可以从集合S中任取一个元素X,将子集的枚举划分成两个子问题:
(1)       子集中含X的,我们可以先枚举S-X的所有子集,然后将X放入生成的结果中,从而构成S的一个含X的子集;
(2)       子集不含X的,我们可以枚举S-X的所有子集,将它们直接作为S的子集。
根据上述思想设计的Prolog程序如下:
% File: subset.pro
domains
 ilist=integer*
 
predicates
 nondeterm subset(ilist, ilist)
 
clauses
 subset([], []).
 subset([X|Set], [X|SubSet]):-subset(Set, SubSet).
 subset([_|Set], SubSet):-subset(Set, SubSet).
 
goal
 subset([1,2,3], Subset),
 write(Subset), nl,
 fail.
 
上述目标生成的结果如下:
[1,2,3]
[1,2]
[1,3]
[1]
[2,3]
[2]
[3]
[]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
下面我们考虑集合的所有K元子集的生成方法。与生成所有子集不同的是,当集合为空集时,只能生成1个0元子集,即空子集;在集合非空的情况下,若子集中含X的,我们可以先枚举S-X的所有(k-1)元子集,然后将X放入生成的结果中,从而构成S的一个含X的k元子集;或者直接枚举S-X的所有k元子集,将它们直接作为S的k元子集。
因此,与生成子集的谓词不同的是,我们需要引入一个三元谓词
 k_subset(K, Set, SubSet)
其中K表示子集元素个数,Set为原集合,而Subset为生成的K元子集。相应的Prolog程序如下:
% File: k-subset.pro
domains
 ilist=integer*
 
predicates
 nondeterm k_subset(integer, ilist, ilist)
 
clauses
 k_subset(0, [], []).
 k_subset(K, [X|Set], [X|SubSet]):-
      K > 0,
      K1 = K - 1,
      k_subset(K1, Set, SubSet).
 k_subset(K, [_|Set], SubSet):-
      k_subset(K, Set, SubSet).
 
goal
 k_subset(3, [1,2,3,4,5], Subset),
 write(Subset), nl,
 fail.
上述目标生成5个元素的全部3元子集:
[1,2,3]
[1,2,4]
[1,2,5]
[1,3,4]
[1,3,5]
[1,4,5]
[2,3,4]
[2,3,5]
[2,4,5]
[3,4,5]
实际上,生成k元子集的方法就是生成n个元素的k个元素的组合方法。
 
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值