如何在Prolog中将无序集划分为子集

时间:2017-09-15 18:30:12

标签: list prolog set

我需要一个将给定集合拆分为子集的谓词

到目前为止我所拥有的:

divide_set(S, Sd) :-
  length(S, L),
  between(1, L, N),
  length(Sd, N),
  append(Sd, S),
  forall(member(M, Sd), M \= []).

这给了我这些结果:

?- divide_set([a, b, c, d, e, f], Sd).
Sd = [[a, b, c, d, e, f]] ;
Sd = [[a], [b, c, d, e, f]] ;
Sd = [[a, b], [c, d, e, f]] ;
Sd = [[a, b, c], [d, e, f]] ;
Sd = [[a, b, c, d], [e, f]] ;
Sd = [[a, b, c, d, e], [f]] ;
...

因此该集合被视为有序集合,但我也希望包含[a, f]

如何扩展谓词以便获取子集而不是子序列?

(我可以为每个可能的序列做到这一点,但我认为这不是最好的解决方案)

1 个答案:

答案 0 :(得分:3)

哇,有点棘手的问题!我的第一个想法是尝试这样的事情,一个陈述性的阅读:

superset(Superset, Subsets) :-
  foreach(member(Subset, Subsets),
    foreach(member(X, Subset), member(X, Superset))).

这在纸面上看起来不错,但使用member/2生成会导致无限递归,因为它会产生包含未绑定变量的大量列表。所以这不起作用。

我的下一个想法是,也许我可以像你建议的那样生成所有排列。但是当我想象生成所有排列然后围绕它们构建所有可能的列表时,它听起来好像会有很多重复的答案。所以我想到了你的意见,这可能是一种更有效的方法。

然后我开始做一些示例输入/输出,看起来像这样:

divide_set([X,Y], [[X],[Y]]).
divide_set([X,Y], [[X,Y]]).

divide_set([X,Y,Z], [[X],[Y],[Z]]).
divide_set([X,Y,Z], [[X],[Y,Z]]).

divide_set([X,Y,Z], [[X,Y],[Z]]).
divide_set([X,Y,Z], [[X,Z],[Y]]).
divide_set([X,Y,Z], [[X,Y,Z]]).

以这种方式对它们进行分组有助于我看到一种方法:我要么拉出前面的项目并重复,要么拉出前面的项目并将其添加到递归结果中,这导致我实现了这个:

divide_set([X], [[X]]).
divide_set([X|Remainder], [[X]|Rest]) :-
    divide_set(Remainder, Rest).
divide_set([X|Remainder], [[X|Subset]|RestButOne]) :-
    divide_set(Remainder, Rest),
    select(Subset, Rest, RestButOne).

我不确定这是否正确,但这是我对您的示例输入的输出:

?- divide_set([1,2,3,4], X).
X = [[1], [2], [3], [4]] ;
X = [[1], [2], [3, 4]] ;
X = [[1], [2, 3], [4]] ;
X = [[1], [2, 4], [3]] ;
X = [[1], [2, 3, 4]] ;
X = [[1, 2], [3], [4]] ;
X = [[1, 3], [2], [4]] ;
X = [[1, 4], [2], [3]] ;
X = [[1, 2], [3, 4]] ;
X = [[1, 3, 4], [2]] ;
X = [[1, 2, 3], [4]] ;
X = [[1, 4], [2, 3]] ;
X = [[1, 2, 4], [3]] ;
X = [[1, 3], [2, 4]] ;
X = [[1, 2, 3, 4]] ;
false.

我没有做过数学计算,看看我们应该在答案的组合方面得到什么,但乍一看,这对我来说是正确的。我看到了所有不同大小的子集,我期望有四个元素,我看到了所有不同数量的子集。随着它进一步进入递归,工作确实减少了;你会注意到数字1从未出现在第二个或后续的列表中,2个从未出现在第3个或第4个子集中,等等。所以我认为这是合理的,这是正确的。

此外,您感兴趣的方案确实发生:

?- divide_set([a, b, c, d, e, f], [[a,f]|Rest]).
Rest = [[b], [c], [d], [e]] ;
Rest = [[b], [c], [d, e]] ;
Rest = [[b], [c, d], [e]] ;
Rest = [[b], [c, e], [d]] ;
Rest = [[b], [c, d, e]] ;
Rest = [[b, c], [d], [e]] ;
Rest = [[b, d], [c], [e]] ;
Rest = [[b, e], [c], [d]] ;
Rest = [[b, c], [d, e]] ;
Rest = [[b, d, e], [c]] ;
Rest = [[b, c, d], [e]] ;
Rest = [[b, e], [c, d]] ;
Rest = [[b, c, e], [d]] ;
Rest = [[b, d], [c, e]] ;
Rest = [[b, c, d, e]] ;
false.