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).
我已经编写了一组子句,它们将告诉我是否存在从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) :-
\+ 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在那个子句中没有真正的用途(或者是真的吗?)