【发布时间】:2013-07-04 15:59:32
【问题描述】:
我正在尝试编写一个序言程序来确定一个列表是否是另一个列表的排列。输入是perm(L,M) 的形式,当且仅当列表L 是列表M 的排列时才会为真。
这是针对我的 AI 课程的,所以我不能只使用 gprolog 已经提供的漂亮的小 permutation 谓词。我们的教授指出,member 谓词可能有用,但我所拥有的任何涉及它的想法似乎都需要非常棘手且不那么声明性的东西(我假设有一种方法可以解决这个问题而不会太先进,因为这个类对于 prolog 来说是新的。)
无论如何,一种检查方法应该是查看L 和M 的大小相同,每个L 元素在M 中,每个M 元素在L 中(有一个使用member!)。但是,对于 [2,2,4] 和 [4,4,2] 等情况,这还不够。
另一种方法可能是确保每个元素的相同计数在相反的列表中,但我对 prolog 的印象是任何类型的变量“内存”都是相当困难的业务(实际上,示例程序似乎我看到执行排序等根本没有真正操纵数据;它们只是“假设地”重新排列事物,然后告诉你是或否......?)
从心理上讲,可以同时对列表进行排序并并排检查元素,但是,在许多其他的思考方式中,这似乎有点过于面向对象......
有什么提示吗?我最大的麻烦似乎是(如前所述)这样一个事实,即进行“操作”似乎更像是询问它们并希望事情保持足够长的时间才能到达你想要的地方。
**更新:gprolog 确实提供了delete 功能,但它带来了我所期待的与声明相关的麻烦,考虑到这样的尝试:
perm([LH|LT], R) :- member(LH,R), delete([LH|LT],LH,R), perm(LT,R).
在手册中,delete 的定义如下:“delete(List1, Element, List2) 删除 List1 中所有出现的 Element 以提供 List2。需要严格的术语相等,参见 (==)/2”
执行:
{trace}
| ?- perm([1,2,3],[3,1,2]).
1 1 Call: perm([1,2,3],[3,1,2]) ?
2 2 Call: member(1,[3,1,2]) ?
2 2 Exit: member(1,[3,1,2]) ?
3 2 Call: delete([1,2,3],1,[3,1,2]) ?
3 2 Fail: delete([1,2,3],1,[3,1,2]) ?
2 2 Redo: member(1,[3,1,2]) ?
2 2 Fail: member(1,[3,1,2]) ?
1 1 Fail: perm([1,2,3],[3,1,2]) ?
(1 ms) no
**更新 2:我想我可能已经想通了!这有点冗长,但我已经测试了很多案例,还没有找到一个不好的案例。如果有人看到重大问题,请指出:
perm([],[]).
perm([LH|LT],R) :- length([LH|LT],A), length(R,B), A == B, member(LH,R), select(LH,[LH|LT],X), select(LH,R,Y), perm_recurse(X, Y), !.
perm_recurse([],X). %If we get here, all elements successfully matched
perm_recurse([LH|LT],R) :- member(LH,R), select(LH,[LH|LT],X), select(LH,R,Y), perm_recurse(X, Y), !.
我确实喜欢 cut 运算符..
【问题讨论】:
-
如果将 L 中的第一个元素与 M 中的一个元素匹配,如果存在,则从 L 和 M 中删除匹配的元素怎么办?然后,您将需要检查较小的列表...
-
怎么样?请参阅更新...不幸的是,
delete似乎实际上并没有像检查您的论点是否构成正确的删除一样多。例如,| ?- delete([1,2,3],1,[2,3]).表示是,因为从 [1,2,3] 中删除 1 会产生 [2,3]。 -
您是否考虑过 [2,2,4] 和 [4,4,2] 的相互排列,还是希望它失败?我认为它应该失败。
-
(请注意,
delete([1,1,2,3],1,X)以X=[2,3]成功。可能不是您需要的)。
标签: prolog logic gnu-prolog