3

我希望我的程序找到整数 1,2,...,N 的所有大小为 K 的子集。

为此,我编写了以下 subs(N,X,Y) 表示 X 是集合 Y 的大小为 N 的子集。我定义了以下内容:

subs(0,[],X).
subs(N,[A|R1],[A|R2]):-N>0, N1 is N-1, subs(N1,R1,R2).
subs(N,[A|R1],[B|R2]):-subs(N,[A|R1],R2).
subs(N,[A|R1],[B|R2]):-subs(N,R1,[B|R2]).

然后作为检查,我运行了 subs(2,X,[1,2,3,4])。

我得到了第一个答案 [1,2],但它从未给出第二个答案,因为它陷入了无限循环。我试图追踪它,似乎在找到第一个答案之后:

   Redo: (8) subs(0, _G613, [3, 4]) ? creep
^  Call: (9) 0>0 ? creep
^  Fail: (9) 0>0 ? creep
   Redo: (8) subs(0, _G613, [3, 4]) ? creep
   Call: (9) subs(0, [_G618|_G619], [4]) ? creep
^  Call: (10) 0>0 ? creep
^  Fail: (10) 0>0 ? creep
   Redo: (9) subs(0, [_G618|_G619], [4]) ? creep
   Call: (10) subs(0, [_G618|_G619], []) ? creep
   Fail: (10) subs(0, [_G618|_G619], []) ? creep
   Redo: (9) subs(0, [_G618|_G619], [4]) ? creep
   Call: (10) subs(0, _G619, [4]) ? creep
   Exit: (10) subs(0, [], [4]) ? creep
   Exit: (9) subs(0, [_G618], [4]) ? creep
   Exit: (8) subs(0, [_G618], [3, 4]) ? creep
   Exit: (7) subs(1, [2, _G618], [2, 3, 4]) ? 

所以我看到我被困住了subs(0, _G619, [4])。有人知道如何克服这个问题吗?

谢谢

4

2 回答 2

4

你的第 4 条有缺陷。第二个参数(子集)的头部有一个A单例变量。该子句基本上读取,[A|R1]是来自的N值的子集,[B|R2]如果R1是来自的N值的子集[B|R2],对于任何变量A。对于子集,这不是正确的规则,并且会导致无限循环,因为它最终不会减少到基本情况。目前尚不清楚这条规则的目的是什么。您可能可以将其删除,因为前 3 个充分定义了子集。

您还应该N在第 3 个子句中进行约束,以避免规则匹配的重复重叠。

这加上一点变量清理使您的谓词成为:

subs(0, [], _).
subs(N, [A|R1], [A|R2]) :- N > 0, N1 is N-1, subs(N1, R1, R2).
subs(N, R1, [_|R2]) :- N > 0, subs(N, R1, R2).
于 2015-03-17T14:32:54.673 回答
2

@lurker 的答案是在谓词的语义级别上。没关系。但是还有一种更简单的方法来识别问题 - 只需使用以下故障切片

潜艇(0,[],_X):-subs(N,[A|R1],[A|R2]):- false , N>0, N1 是 N-1, subs(N1,R1,R2)subs(N,[A|R1],[_B|R2]):- false , subs(N,[A|R1],R2)。
subs(N,[_A|R1],[B|R2]):- subs(N,R1,[B|R2]), false

这个片段已经不会终止了subs(2,X,[1,2,3,4])。但是,它应该这样做。因此,在剩余的可见部分中,您需要解决一个问题。

有一个标准可以找到这个失败片段:查询的(通用)不终止。没有关于实际预期含义的进一步信息用于确定该切片。

于 2015-03-17T16:55:34.950 回答