【问题标题】:gprolog - Simple way to determine whether one list is a permutation of anothergprolog - 确定一个列表是否是另一个列表的排列的简单方法
【发布时间】:2013-07-04 15:59:32
【问题描述】:

我正在尝试编写一个序言程序来确定一个列表是否是另一个列表的排列。输入是perm(L,M) 的形式,当且仅当列表L 是列表M 的排列时才会为真。

这是针对我的 AI 课程的,所以我不能只使用 gprolog 已经提供的漂亮的小 permutation 谓词。我们的教授指出,member 谓词可能有用,但我所拥有的任何涉及它的想法似乎都需要非常棘手且不那么声明性的东西(我假设有一种方法可以解决这个问题而不会太先进,因为这个类对于 prolog 来说是新的。)

无论如何,一种检查方法应该是查看LM 的大小相同,每个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


【解决方案1】:

定义更一般的谓词并以狭窄的方式使用它总是好的:

perm(X,L):- mselect(X,L,[]).

mselect([A|B],L,R):- select(A,L,M), mselect(B,M,R).
mselect([],L,L).

member 不好,因为它使第二个列表保持不变。 delete 也不好,因为它删除了多重性。

你可以使用append。 :) 它也结合了拾取和移除:

perm([A|B],L):- length(L,N), between(0,N,I),length(X,I),
  append(X,[A],Y), append(Y,Z,L),
  append(X,Z,M), perm(B,M).
perm([],[]).

【讨论】:

  • 我喜欢第一个想法,并注意到我必须做一些类似于mselect([],L,L) 行的事情来防止失败。我对它相当冗长的破解现在被添加到编辑中的问题中。 :-)
【解决方案2】:
perm(L, M) :- sort(L, X), sort(M, X).

这让您非常接近并且是完全声明性的(“如果两个列表具有相同的排序表示,则它们是彼此的排列”,但在 Prolog 中排序会删除重复项)。但是,对于像 perm([1,2], [2,2,2,1]) 这样的情况,它会成功,我不确定你是否想要。不过,它将处理 [2,2,4] 和 [4,4,2],因为它们都排序为 [2,4]。另一种解决方案是这样的:

perm([], []).
perm([L|Ls], M) :- select(L, M, Ms), !, perm(Ls, Ms).

此版本对于 [2,2,4] 和 [4,4,2] 不会成功,但对于 [1,2] 和 [2,2,2,1] 会正常失败。我不确定你想要哪一个,但我认为其中一个可能是正确的。

【讨论】:

  • 嗯,至少部分正确。 :-) 我可能需要留在第二个附近,因为下一个问题需要我实际编写一个使用此permsort
  • msort 不会消除重复项,因此如果 L 是 M 的排列,则 msort(L, X), msort(M, X) 为真
  • sort/2 本身不是声明性的,因此您的 perm/2 也不能是声明性的......
  • @false 是什么让你说sort/2 不是声明性的?
  • sort([X,1],[2,1]), X = 2. 成功,但 X = 2, sort([X,1],[2,1]). 失败。含义取决于调用sort/2的时间点的精确实例化。
【解决方案3】:

通常遵循的模型是归纳

如果您知道如何构建 N-1 个元素的所有排列,则可以通过将元素插入所有可用位置来获得 N 个元素的所有排列。

“交易技巧”是使用 select/3 内置函数,与 member 一样,“窥视”一个元素,但 将其从列表中删除并“返回”较小的列表。这些动词并不适合 Prolog。假设 select/3 是一个元素、一个包含它的列表和一个缺少它的相同列表之间的关系

然后让 Prolog 做所有的搜索……结果代码真的很小……

【讨论】:

  • select 还不只是做检查吗?例如,这不起作用,因为右侧列表没有更改:perm([LH|LT], R) :- select(LH,[LH|LT],R), perm(LT,R). 也许我错过了我需要的另一个嵌入级别?这个基本上只是说,“R 是去掉 L 的头的结果吗?”当然不是,因为那是我想要实现的目标,而不是现在的真实情况。
  • @nicole,根据 GNU Prolog 手册,“select(Element, List1, List2) 删除了 List1 中出现的 Element 以提供 List2。”
  • 确实如此。但是当我运行它时,情况似乎并非如此。
  • @nicole, select/3 应该一直做同样的事情,因为它的设计,除非你使用别人的自定义版本。 :) 所以还有其他事情出错了。如果您想在使用它的地方显示您的代码,我们可以解决该问题。
  • 这是我的第一条评论。执行时的跟踪是这样的: {trace} | ?-烫发([1,2,3],[3,1,2])。 1 1 调用: perm([1,2,3],[3,1,2]) ? 2 2 调用:select(1,[1,2,3],[3,1,2]) ? 2 2 失败:select(1,[1,2,3],[3,1,2]) ? 1 1 失败:perm([1,2,3],[3,1,2]) ?没有
【解决方案4】:

只需对两个列表进行排序并比较结果

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-04-08
    • 2021-01-04
    • 2012-10-08
    • 2010-09-30
    • 1970-01-01
    • 1970-01-01
    • 2013-11-05
    相关资源
    最近更新 更多