List 在Prolog中遍历图(带有可能的循环)并返回路径

List 在Prolog中遍历图(带有可能的循环)并返回路径,list,prolog,transitive-closure,meta-predicate,List,Prolog,Transitive Closure,Meta Predicate,我得到了一个弧的列表: arc(a,b). arc(b,c). arc(c,d). arc(d,b). arc(d,e). arc(e,e). arc(e,f). 我已经编写了一组子句,它们将告诉我是否存在从nodeX到nodeY的路径。循环可能发生,我已经解释过了 path(X,Y) :- arc(X,Y). path(X,Y) :- arc(X,Z), path(Z,Y,[X]). path(X,Y,P) :- arc(X,Y). path(X,Y,P)

我得到了一个弧的列表:

arc(a,b).
arc(b,c).
arc(c,d).
arc(d,b).
arc(d,e).
arc(e,e).
arc(e,f).
我已经编写了一组子句,它们将告诉我是否存在从node
X
到node
Y
的路径。循环可能发生,我已经解释过了

path(X,Y) :-
    arc(X,Y).
path(X,Y) :-
    arc(X,Z),
    path(Z,Y,[X]).

path(X,Y,P) :-
    arc(X,Y).
path(X,Y,P) :-
    \+ member(X,P),
    arc(X,Z),
    append([X],P,L),
    path(Z,Y,L).
我需要修改它,以便在成功时返回已遍历的节点列表。我不清楚该怎么做

我假设我的基本情况类似于
path2(X,Y,[X,Y]):-arc(X,Y)。
但这不适用于我的程序。上一部分的解决方案是否有问题,或者只是缺少了一个小的修改?任何帮助都将不胜感激。谢谢

关闭。。。但请考虑:

path(Start, End, Path) :-
    path(Start, End, [], Path).
使用开始和结束节点调用
path/3
将在它们之间构建路径(如果存在),并回溯以提供备用路由。没有节点被访问两次。
[]
是一个节点累加器列表,因此我们可以检查在构建路径时我们是否在循环

path(Now, End, Acc, Path) :-
    arc(Now, Mid),
    Mid == End, !,
    append(Acc, [Now, End], Path).

path(Now, End, Acc, Path) :-
    arc(Now, Mid),
    \+ member(Mid, Acc),
    path(Mid, End, [Now|Acc], Path).
这些谓词完成实际工作。第一种是基本情况,通过另一个调用
arc/2
到达结束节点;在这种情况下,已经建立了一条路径。第二个遍历(定向)图,但只遍历尚未访问的节点

使用
findall/3
可通过以下方式一次定位所有路径:

findall(Path, path(Start,End,Path), Paths).

对于节点原子的
Start
End
的绑定值。

sharky给出的答案似乎不适用于我,但下面的mod确实适用,而且对我来说更直观:

path(Now, End, Acc, [Now,End]) :-
    arc(Now, End),
    \+ member(Now, Acc),
    \+ member(End, Acc).

path(Now, End, Acc, Path) :-
    arc(Now, Mid),
    \+ member(Mid, Acc),
    path(Mid, End, [Now|Acc], Path).
如果我遗漏了什么,一定要告诉我。

移动到a并使用1作为基本习惯用法

% your binary predicate arc/2 gets used here % | % v ?- path(arc, Path, From, To). From = To , Path = [To] ; From = a, To = b, Path = [a,b] ; From = a, To = c, Path = [a,b,c] ; From = a, To = d, Path = [a,b,c,d] ; From = a, To = e, Path = [a,b,c,d,e] ; From = a, To = f, Path = [a,b,c,d,e,f] ; From = b, To = c, Path = [b,c] ; From = b, To = d, Path = [b,c,d] ; From = b, To = e, Path = [b,c,d,e] ; From = b, To = f, Path = [b,c,d,e,f] ; From = c, To = d, Path = [c,d] ; From = c, To = b, Path = [c,d,b] ; From = c, To = e, Path = [c,d,e] ; From = c, To = f, Path = [c,d,e,f] ; From = d, To = b, Path = [d,b] ; From = d, To = c, Path = [d,b,c] ; From = d, To = e, Path = [d,e] ; From = d, To = f, Path = [d,e,f] ; From = e, To = f, Path = [e,f] ; false. %这里使用的是二进制谓词arc/2 % | %五 ?-(弧、路径、从、到)。 From=To,Path=[To] ; From=a,To=b,Path=[a,b] ; From=a,To=c,Path=[a,b,c] ; From=a,To=d,Path=[a,b,c,d] ; From=a,To=e,Path=[a,b,c,d,e] ; From=a,To=f,Path=[a,b,c,d,e,f] ; From=b,To=c,Path=[b,c] ; From=b,To=d,Path=[b,c,d] ; From=b,To=e,Path=[b,c,d,e] ; From=b,To=f,Path=[b,c,d,e,f] ; From=c,To=d,Path=[c,d] ; From=c,To=b,Path=[c,d,b] ; From=c,To=e,Path=[c,d,e] ; From=c,To=f,Path=[c,d,e,f] ; From=d,To=b,Path=[d,b] ; From=d,To=c,Path=[d,b,c] ; From=d,To=e,Path=[d,e] ; From=d,To=f,Path=[d,e,f] ; From=e,To=f,Path=[e,f] ; 错。

脚注1:由多面手实现。

您试图通过“路径(X,Y,p):-弧(X,Y)”实现什么?(最好确保头部的所有变量也存在于身体中。)这是基本情况。一旦我们从当前节点(X)到最终节点(Y)有了一条弧,我们就找到了一条路径。P是我们已经访问过的节点列表。我理解你的意思,也同意P在那个子句中没有真正的用途(或者是真的吗?)