3

我想在有向图中打印节点的路径。此代码适用于边缘,但不适用于整个路径。当涉及到路径时,它返回 false。这是我的代码,但它仅针对边缘而不是整个路径运行。请帮帮我。

这是我的代码:

path(Node1, Node2, X) :-
  edge(Node1, Node2),
  append([Node1], [Node2], X).
path(Node1, Node2, X, N) :-
  edge(Node1, SomeNode),
  append([Node1], [SomeNode], X),
  path(SomeNode, Node2, X, N),
  append([], [Node2], X).

X是一个列表。

4

2 回答 2

4

虽然@WouterBeek 已经指出了您的问题,但 Wouter 的声明

如果不运行此代码,您已经可以观察到第二个子句总是会失败,因为长度为 2 的列表不能与长度为 1 的列表统一

值得详细说明。对于有经验的 Prolog 程序员来说,很容易发现这些问题。但是初学者能做什么呢?他们可以应用以下技术: 泛化你的程序,如果泛化的程序仍然过于专业,那么剩下的部分肯定有错误。

泛化一个纯 Prolog 程序

有几种方法可以泛化纯 Prolog 程序:要么删除目标,要么删除头部或目标参数中的子项。要删除目标,我将*在目标前添加一个,使用:

:- op(950,fy, *)。

*_。

路径(节点 1,节点 2,X):-
  * 边缘(节点1,节点2),
  追加([节点 1],[节点 2],X)。
路径(节点 1,节点 2,X):-
  * 边缘(Node1,SomeNode),
  附加([Node1],[SomeNode],X),
  *  path(SomeNode, Node2, X) ,
  追加([],[Node2],X)。

现在我们可以询问这个新谓词的最一般查询:

| ?- path(N1, N2, P).
P = [N1,N2] ? ;
no

因此:虽然这个定义现在是一个(过度)概括,但它仍然只承认长度为 2 的路径。这个问题完全独立于 的定义edge/3,只有剩下的部分负责。所以看看剩下的部分来解决问题!

于 2014-04-20T21:45:23.477 回答
3

在您的第二个子句中,您有以下两个语句:

append([Node1], [SomeNode], X),
append([], [Node2], X).

请注意,两个语句中都出现了变量X,并且必须将其实例化为同一个列表。这意味着[Node1]+[SomeNode] = []+[Node2][Node1,SomeNode]=[Node2]

如果不运行此代码,您已经可以观察到第二个子句总是会失败,因为长度为 2 的列表不能与长度为 1 的列表统一。

还有一点:这两个子句不属于同一个谓词,因为前者的元数为 3,而后者的元数为 4。通常,为了计算路径或任意深度,您需要一个由两个属于一起的子句组成的谓词:基本情况和递归情况。对于递归情况,使用头/尾符号来构造路径是一种常见的做法:[FromNode,ToNode|RestOfPath].

希望这可以帮助!

于 2014-04-19T23:08:35.027 回答