我正在尝试编写一个Prolog程序,为我提供图形中两点之间的所有可能路径(带循环)。
edge(a,b).
edge(a,c).
edge(a,d).
edge(b,e).
edge(c,e).
edge(c,f).
edge(d,f).
edge(f,g).
edge(g,e).
edge(e,a).
show_path(X,Y,[X,Y]) :- edge(X,Y).
show_path(X,Z,[X|T]) :- edge(X,Y), not(member(Y, T)), show_path(Y,Z,T).
我正在尝试使用not(member())
来排除循环并避免无限循环,但它不会产生所有可能的解决方案。如何更改程序以获得带有循环的图形中两点之间的所有可能路径?
答案 0 :(得分:1)
当T未实例化时,您可以很容易地看到not(member(Y, T))
失败。例如,尝试:
?- not(member(X,L)).
false.
你看到它失败了。要解决此问题,您需要保留一个额外的列表,该列表将在以空列表开头的每个步骤中实例化:
show_path(X,Y,R):-show_path(X,Y,[],R).
show_path(X,Y,_,[X,Y]) :- edge(X,Y).
show_path(X,Y,L,[X|R]) :- edge(X,Z),\+member(Z,L),
show_path(Z,Y,[Z|L],R).
示例:
?- show_path(a,e,L).
L = [a, b, e] ;
L = [a, b, e, a, c, e] ;
L = [a, b, e, a, c, f, g, e] ;
L = [a, b, e, a, d, f, g, e] ;
L = [a, c, e] ;
L = [a, c, e, a, b, e] ;
L = [a, c, e, a, d, f, g, e] ;
L = [a, c, f, g, e] ;
L = [a, c, f, g, e, a, b, e] ;
L = [a, d, f, g, e] ;
L = [a, d, f, g, e, a, b, e] ;
L = [a, d, f, g, e, a, c, e] ;
false.
你可以通过写一下@Fatalize建议输出:
show_path(X,Y,[X,Y]) :- edge(X,Y).
show_path(X,Y,R) :- edge(X,Z), show_path(Z,Y,RZ),R=[X|RZ],
sort(R,R1),length(R,N),length(R1,N1),
(N>N1->!,fail ;true).
示例:
?- show_path(a,e,L).
L = [a, b, e] ;
L = [a, c, e] ;
L = [a, c, f, g, e] ;
L = [a, d, f, g, e] ;
false.
答案 1 :(得分:1)
您的程序无效,因为not(member(Y, T))
始终为false:此时T
未实例化,因此始终可以找到包含Y
的列表
您可以通过添加累加器修复程序:
show_path(X,X,T,P) :- reverse([X|T],P).
show_path(X,Z,T,P) :- edge(X,Y), not(member(X,T)), show_path(Y,Z,[X|T],P).
show_path(X,Y,P) :- show_path(X,Y,[],P).
通过避免循环不清楚你的意思。与@ coder的答案不同,它会避免在同一点上传递两次。例如:
?- show_path(a,e,Z).
Z = [a, b, e] ;
Z = [a, c, e] ;
Z = [a, c, f, g, e] ;
Z = [a, d, f, g, e] ;
false.