Prolog:查找只有两个状态的元素列表的所有可能排列

时间:2018-03-21 23:33:27

标签: prolog combinations permutation

我试图在只有两种状态的元素Prolog中实例化多个列表,状态为红色和蓝色。最初,我通过创建大小为n的列表来实例化一个仅为蓝色的元素列表:

generate_list(0, []) :- !.
generate_list(N, [H | T]) :-
  N2 is N-1,
  H = blue,
  generate_list(N2, T).

我还定义了一个谓词来改变颜色状态

flip(blue, red).
flip(red, blue).

我想在新列表的实例化过程中使用这个谓词来改变颜色,但是我仍然坚持如何解决这个问题。默认排列和组合谓词要求您使用单独的预定义元素来实例化新列表,但是我有一个已生成的元素列表。

1 个答案:

答案 0 :(得分:2)

从你的问题中不清楚你的意思是什么"改变"实例化期间的颜色""。如果你可以用你想要的具体例子来更新它,那就太好了。

然而,这可能会或可能不会朝着你想要的方向发展:

color(red).
color(blue).

colorlist([]).
colorlist([C|Cs]) :-
    color(C),
    colorlist(Cs).

colorlist/2的定义表明它的参数是一个列表,其元素满足color/1。两种颜色都可以,因此redblue中任何元素排列的任何列表都是一种解决方案。我们已经可以使用它来检查颜色列表:

?- colorlist([red, blue, blue]).
true.

并且尝试枚举它们,虽然枚举不公平,即一些解决方案(在这种情况下,包含blue的任何列表)将永远不会生成:

?- colorlist(Cs).
Cs = [] ;
Cs = [red] ;
Cs = [red, red] ;
Cs = [red, red, red] ;
Cs = [red, red, red, red] ;
Cs = [red, red, red, red, red] . % etc.

为了解决公平性问题,我们可以按长度进行枚举:首先是所有长度为0的列表,然后是所有长度为1的列表,所有长度为2的等等。如果我们将长度作为参数公开,我们获得至少与您尝试编写的谓词具有相同接口的内容:

length_colorlist(N, Cs) :-
    length(Cs, N),
    colorlist(Cs).

这可以公平而一般地列举解决方案:

?- length_colorlist(N, Cs).
N = 0,
Cs = [] ;
N = 1,
Cs = [red] ;
N = 1,
Cs = [blue] ;
N = 2,
Cs = [red, red] ;
N = 2,
Cs = [red, blue] ;
N = 2,
Cs = [blue, red] .

并回答受长度限制的更具体的问题:

?- length_colorlist(8, Cs).
Cs = [red, red, red, red, red, red, red, red] ;
Cs = [red, red, red, red, red, red, red, blue] ;
Cs = [red, red, red, red, red, red, blue, red] ;
Cs = [red, red, red, red, red, red, blue, blue] ;
Cs = [red, red, red, red, red, blue, red, red] ;
Cs = [red, red, red, red, red, blue, red, blue] ;
Cs = [red, red, red, red, red, blue, blue, red] ;
Cs = [red, red, red, red, red, blue, blue, blue] ;
Cs = [red, red, red, red, blue, red, red, red] ;
Cs = [red, red, red, red, blue, red, red, blue] .

注意:不需要剪切,最终定义是由更通用,个别有用的部分组成的简单组合。当遇到问题时,特别是在Prolog中,总是先尝试解决各个子部分。在这种情况下,"如何定义包含颜色的列表(任何长度)?"和"如何生成特定长度的列表?"是两个不同的子问题,最好分开解决。