1

立方体

这是一个立方体,它的边缘是有方向的;它只能从左到右,从后到前,从上到下。

edge(a,b).
edge(a,c).
edge(a,e).
edge(b,d).
edge(b,f).
edge(c,d).
edge(c,g).
edge(d,h).
edge(e,f).
edge(e,g).
edge(f,h).
edge(g,h).

使用下面的方法,我们可以检查是否可以从 AH 出发,例如:cango(A,H)。

move(X,Y):- edge(X,Y).
move(X,Y):- edge(X,Z), move(Z,Y).

使用 move2,我正在尝试执行所需步骤的计数。

move2(X,Y,N):- N is N+1, edge(X,Y).
move2(X,Y,N):- N is N+1, edge(X,Z), move2(Z,Y,N).

我将如何实现这一点?

4

3 回答 3

2

算术评估在 Prolog 中像往常一样进行,但赋值不能像往常一样工作。然后你需要引入一个变量来增加值:

move2(X,Y,N,T):- T is N+1, edge(X,Y).
move2(X,Y,N,T):- M is N+1, edge(X,Z), move2(Z,Y,M,T).

并在第一次调用时将 N 初始化为 0。这种添加的变量(在我们的例子中是 T)通常被称为累加器

于 2012-10-29T12:28:55.083 回答
1
move2(X,Y,1):- edge(X,Y), ! .
move2(X,Y,NN):- edge(X,Z), move2(Z,Y,N), NN is N+1 .
于 2012-10-29T14:33:11.693 回答
1

(is)/2对第二个参数中的实例化非常敏感。这意味着您不能以完全相关的方式使用它。你可以问X is 1+1.,你甚至可以问2 is 1+1.但你不能问:2 is X+1

因此,当您使用诸如 之类的谓词进行编程时(is)/2,您必须想象谓词将用于哪些模式。这样的考虑很容易导致错误,特别是如果您刚刚开始。但不用担心,更熟练的程序员仍然会遇到此类问题。

在几个 Prolog 系统中有一个干净的替代方案:在 SICStus、YAP、SWI 中,有一个library(clpfd)允许您表达整数之间的关系。通常这个库用于约束编程,但您也可以将它用作(is)/2整数的安全和干净的替代品。更重要的是,这个库通常被非常有效地编译,使得生成的代码在速度上与(is)/2.

?- 使用模块(库(clpfd))。
真的。

?- X #= 1+1。
X = 2。

?- 2 #= 1+1。
真的。

?- 2 #= X+1。
X = 1。

所以现在回到你的程序,你可以简单地写:

移动2(X,Y,1):-边缘(X,Y)。
move2(X,Y,N0):- N0 #>= 1, N0 #= N1+1, edge(X,Z), move2(Z,Y,N1)。

您现在可以根据需要获得所有距离。

但还有更多...

为确保move2/3实际终止,请尝试:

?- move2(A, B, N),假的。
错误的。

现在我们可以确定它move2/3总是终止。总是?假设您添加了进一步的优势:

edge(f, f).

现在上面的查询循环。但是您仍然可以使用您的程序来发挥自己的优势!确定节点数:

?- setof(C,A^B^(edge(A,B),member(C,[A,B])),Cs), 长度(Cs, N)。
Cs = [a, b, c, d, e, f, g, h],
N = 8。

所以最长的路径只需 7 步!

现在您可以再次询问查询,但现在通过限制N为小于或等于 7 的值:

?- 7 #>= N, move2(A,B, N), false。
错误的。

有了这个额外的约束,你又得到了一个终止定义!没有更多的循环。

于 2012-10-29T17:32:25.427 回答