我有一个带有入口和出口节点的循环图,我想为其找出所有从入口到出口节点的所有路径。
entry(a).
exit(e).
exit(f).
next(a, b).
next(b, c).
next(b, d).
next(c, e).
next(d, f).
/* Cycle */
next(c, d).
next(d, b).
/* path(entrynode, exitnode, pathtrace) */
path(X, Y, P) :- entry(X), path2(X, Y, P).
path2(X, Y, [Y]) :- next(X, Y), exit(Y).
path2(X, Y, [P|PS]) :- next(X, P), path2(P, Y, PS).
我的path2谓词在非循环图上很好用。现在我想将其扩展到循环的。我要做的就是检查访问的节点列表中是否已经有新的可能节点。为此,我将not(member(X, PS))
添加到我的最后一条规则中。
如果我在递归之前添加它,则它总是返回false。如果在递归之后添加它,那么Prolog会尝试首先查找路径并耗尽堆栈。它会返回正确的答案,但会尝试找到更多答案并陷入困境。
因此:我应该在哪里添加支票,或者我做错了什么/我可以做得更好?
答案 0 :(得分:1)
您的path2/3
谓词需要一个附加参数,因为您的第三个参数是正在构建的路径,而不是已访问节点的列表。即您不能简单地将\+ member(X,Ps)
目标添加到谓词的最后一条规则,因为Ps
受递归调用的约束。请尝试:
path(X, Y, P) :-
entry(X),
path2(X, Y, [], P).
path2(X, Y, _Visited, [Y]) :-
next(X, Y),
exit(Y).
path2(X, Y, Visited, [P|PS]) :-
next(X, P),
\+ member(P, Visited),
path2(P, Y, [P| Visited], PS).
通话示例:
| ?- path(X, Y, P).
P = [b,c,e]
X = a
Y = e ? ;
P = [b,c,d,f]
X = a
Y = f ? ;
P = [b,d,f]
X = a
Y = f ? ;
no