我知道最初的问题是很久以前发布的,但我最近也在解决 Prolog 的艺术 中的一些问题,并考虑了偶数/奇数排列问题几天。我不想打开重复的问题,所以我在这里发布我的解决方案。
书中的问题问:
为even_permutation(Xs, Ys) 和odd_permutation(Xs,
Ys) 编写程序找到Ys,分别是偶数和奇数排列,
列表Xs。例如,even_permutation([1,2,3], [2,3,1]) 和
odd_permutation([1,2,3], [2,1,3]) 是真的。
所以它需要置换生成器,而不仅仅是验证器。 @hardmath 提供了偶数或奇数排列的正确定义的链接。本书的作者举了两个简单的例子来说明。
对我来说,关键是找出偶数或奇数排列的递归定义。对于所有排列,Prolog 中的经典排列生成器使用以下概念:
- N+1 个元素的每个排列都是一个列表,表示 N 个元素的排列,其中第 (N+1) 个元素插入到列表中。
谓词select 或insert 用于进行插入。
对于偶数和奇数排列,我考虑过类似的想法:
N+1 个元素的每个 even 排列是一个列表,表示 N 个元素与第 (N+1) 个元素的 even 排列插入到列表中的 odd 位置,或表示 N 个元素的 odd 排列的列表,其中第 (N+1) 个元素插入到 甚至在列表中的位置。
N+1 个元素的每个 odd 排列是一个列表,表示 N 个元素与第 (N+1) 个元素的 odd 排列插入到列表中的 odd 位置,或者表示 N 个元素的 even 排列的列表,其中第 (N+1) 个元素插入到 甚至在列表中的位置。
合理的是,在奇数位置插入元素表示相对于原始列表的偶数交换(列表的前面,作为第一个位置,不需要交换,所以它是偶数)。类似地,在偶数位置插入元素表示相对于原始列表的奇数交换。
如果我添加空列表是它自己的偶排列的规则,那么我可以定义以下谓词来生成偶排列和奇排列:
even_permutation( [], [] ).
even_permutation( [X|T], Perm ) :-
even_permutation( T, Perm1 ),
insert_odd( X, Perm1, Perm ).
even_permutation( [X|T], Perm ) :-
odd_permutation( T, Perm1 ),
insert_even( X, Perm1, Perm ).
odd_permutation( [X|T], Perm ) :-
odd_permutation( T, Perm1 ),
insert_odd( X, Perm1, Perm ).
odd_permutation( [X|T], Perm ) :-
even_permutation( T, Perm1 ),
insert_even( X, Perm1, Perm ).
insert_odd( X, InList, [X|InList] ).
insert_odd( X, [Y,Z|InList], [Y,Z|OutList] ) :-
insert_odd( X, InList, OutList ).
insert_even( X, [Y|InList], [Y,X|InList] ).
insert_even( X, [Y,Z|InList], [Y,Z|OutList] ) :-
insert_even( X, InList, OutList ).