我试图解决这个问题并且我已经阅读了this回答,但即使我使用过访问过的节点列表,我的问题仍然是infinte循环。
让我们看看我的两次尝试:
edge(1,2).
edge(1,4).
edge(1,3).
edge(2,3).
edge(2,5).
edge(3,4).
edge(3,5).
edge(4,5).
% ------ simple path finding in a directed graph
% ----- simple exploration
path0(A,B, Result) :-
path0(A, B, [], Result).
path0(A, B, _, [e(A,B)]):-
edge(A,B).
path0(A, B, Visited, [e(A,X)|Path]):-
edge(A, X), dif(X, B),
\+ member(X, Visited),
path0(X, B, [A|Visited], Path ).
%---- 1. exploration and length
path(A, B, _, [e(A,B)], 1):-
edge(A,B).
path(A, B, Visited, [e(A,X)|Path], Length):-
edge(A, X),
\+ member(X, Visited),
length(Path, L), % ERR: Path refers to a open list
Length is L + 1,
path(X, B, [A|Visited], Path, _).
% --- 2. not working
path2(A,B, Result, Length) :-
path2(A, B, [], Result, Length).
path2(A, B, [], [e(A,B)], 1):-
edge(A,B).
path2(A, B, Visited, [e(A,X)|Path], Length):-
edge(A, X), dif(X, B),
\+ member(X, Visited),
path2(X, B, [A|Visited], Path, Len),
Length is Len + 1.
这给了我类似的答案,即:
?- path(1,3, Path, Length).
Path = [e(1, 3)],
Length = 1 ;
Path = [e(1, 2), e(2, 3)],
Length = 2 ;
然后Swi-Prolog IDE冻结了。
我想摆脱长度/ 2使用。 感谢。
修改
所以,我发现这应该是更干净的方式,即使我想要更类似于第二个实现的东西更容易在最短路径问题求解器中进行转换,因为它只是一分钟第一次调用path3 / 4时的{pathLengths}。
% ---- 3. working
%
min(A,B,A):- A =< B, !. % for future use (shortest path)
min(_,B,B).
path3(From, To, Path, Len):-
path0(From, To, [], Path),
length(Path, Len).
%min(Len, MinLength, ?)
这是第二个实现路径2的更正版本:
% --- 2.
% errors: 1. in base case I have to return Visited trough _,
% I can't pass a void list []
% 2. dif(X,B) is unuseful since base case it's the first clause
path2(A,B, Result, Length) :-
path2(A, B, [], Result, Length).
path2(A, B, _, [e(A,B)], 1):- % If an edge is found
edge(A,B).
path2(A, B, Visited, [e(A,X)|Path], Length):-
edge(A, X),
%tab(1),write(A),write('-'),write(X),
\+ member(X, Visited),
%tab(1),write([A|Visited]),write(' visited'),nl,
path2(X, B, [A|Visited], Path, Len),
Length is Len + 1.
答案 0 :(得分:3)
path/4
和path2/4
两者都暴露相似的非终止行为的原因是因为两者都使用相同的辅助谓词path/5
。你的意思可能是path2/5
:
path2(A,B, Result, Length) :-
path(A, B, [], Result, Length).
% ^^^^ replace by path2
也许首先,让我们看看为什么你的path/4
定义循环。要看到这一点,我会在您的计划中插入 false
目标。这些目标将减少推理的数量。当剩下的片段仍然循环时,我们可以确定我们看到一个负责非终止的部分。经过一些实验,我发现了以下片段,称为failure-slice:
edge(1,2).edge(1,4) :- false.edge(1,3) :- false.edge(2,3) :- false.edge(2,5) :- false.edge(3,4) :- false.edge(3,5) :- false.edge(4,5) :- false. path(A,B, Result, Length) :- path(A, B, [], Result, Length), false.path(A, B, _, [e(A,B)], 1):- false,edge(A,B). path(A, B, Visited, [e(A,X)|Path], Length):- edge(A, X), \+ member(X, Visited), length(Path, L), false,Length is L + 1,path(X, B, [A|Visited], Path, _).
所以基本上是使用length/2
谓词。只要路径的长度不固定,该片段就不会终止。所以对于查询
?- path(1, 3, Path, N).
Path
的长度不受限制,因此length/2
会找到无限多的解决方案 - 因此不会终止。
但是,毕竟,为什么你想知道长度呢? path参数已经隐式地描述了它。
对于您的定义path/4,5
,请考虑查询
?- path(1, X, Path, N).
应该作为答案产生。 Path = [1]
也应该是一个解决方案吗?这是一个关于路径/步行的确切定义的问题。我认为应该。
有关通用解决方案,请参阅this answer。有了它,您可以定义您感兴趣的谓词:
yourpath(A,B, Path, N) :-
path(edge, Path, A,B),
length(Path, N).
但是,我宁愿不添加关于路径长度的额外参数。您可以随时随时添加该信息。