gprolog - 确定一个列表是否是另一个列表的排列的简单方法

时间:2013-07-04 15:59:32

标签: prolog logic artificial-intelligence gnu-prolog

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

这是我的AI课程,所以我不能只使用gprolog已经提供的漂亮的小permutation谓词。我们的教授注意到member谓词可能有用,但我所涉及的任何想法似乎都需要非常棘手且不那么具体的事情(而且我假设有一种方法可以解决这个问题而不会得到太先进了,因为这个课程是prolog的新手。)

无论如何,检查的一种方法应该是LM大小相同,每个L元素都在M中,每个{{} 1}}元素在M中(使用L!)。但是,对于member[2,2,4]等案例而言,这还不够。

另一种方法可能是确保每个元素的相同数量都在相反的列表中,但我对prolog的印象是任何类型的变量“内存”都是相当困难的业务(事实上,它似乎是示例程序我看到执行排序等等根本就没有真正操纵数据;它们只是'假设'重新排列事物然后告诉你是或否......?)

在精神上,人们可以对两个列表进行排序并并排检查元素,但是,在其他许多方法中,这似乎有点过于面向对象......

任何提示?我最大的麻烦似乎是(如上所述)做“操作”似乎更像是询问关于他们的事实,并希望事情保持足够长的时间以达到你想要的地方。

**更新:gprolog确实提供了[4,4,2]功能,但它附带了我期待的与声明相关的麻烦,给出了这样的尝试:

delete

在手册中,删除定义如下:“delete(List1,Element,List2)删除List1中所有出现的Element以提供List2。需要严格的术语相等,cf。(==)/ 2”< / p>

执行:

perm([LH|LT], R) :- member(LH,R), delete([LH|LT],LH,R), perm(LT,R).

**更新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

我喜欢切割操作符..

4 个答案:

答案 0 :(得分: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]会失败。我不确定你想要哪一个,但我认为其中一个或另一个可能是正确的。

答案 1 :(得分:2)

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

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([],[]).

答案 2 :(得分:1)

通常的模型是归纳

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

交易的诀窍&#39;正在使用select / 3内置,就像成员一样,&#39; peek&#39;一个元素,但从列表中删除,然后返回&#39;较小的清单。那些动词并不适合Prolog。让我们说select / 3是元素之间的 relation ,包含它的列表,以及缺少它的相同列表。

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

答案 3 :(得分:0)

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