问题是你没有在你已经去过的地方记账。现在说你正在寻找从sasktchewan
到manitoba
。Prolog 会将其评估为:
(sasktchewan) <--------------
`--(alberta) \
`--(british_columbia) |
|--(yukon) fail! |
`--(nwt) |
`-(sasktchewan)---/
现在,由于您不告诉 prolog 您不能进入循环,因此它将继续附加(sasktchewan) -> (alberta) -> (nwt)
到路径并且永远找不到目标。
演示:
?- route(sasktchewan,manitoba,L).
L = [go(sasktchewan, alberta), go(alberta, saskatchewan), go(saskatchewan, manitoba)] ;
L = [go(sasktchewan, alberta), go(alberta, saskatchewan), go(saskatchewan, manitoba), go(manitoba, nwt), go(nwt, manitoba)] ;
L = [go(sasktchewan, alberta), go(alberta, saskatchewan), go(saskatchewan, nwt), go(nwt, manitoba)] ;
L = [go(sasktchewan, alberta), go(alberta, nwt), go(nwt, manitoba)] ;
L = [go(sasktchewan, alberta), go(alberta, nwt), go(nwt, saskatchewan), go(saskatchewan, manitoba)] ;
L = [go(sasktchewan, alberta), go(alberta, nwt), go(nwt, manitoba), go(manitoba, saskatchewan), go(saskatchewan, manitoba)] ;
你需要做的是使用一个累加器,列出你去过的所有地方。每次您从访问该城市的那一刻起进行会员检查,您就会崩溃。因此:
%We start a route with being in city A
route(A, B, L) :-
route(A, B,[A], L).
%In case we find a city with a border, don't hesitate and go to the city!
route( A, B,_,[go(A,B)]) :-
borders(A,B).
%Too bad, now looking for an extra city
route(A,B,Been,[go(A,Z)|ZtoB]) :-
borders(A,Z), %hahaa, we can access city Z
\+ member(Z,Been), %hold on! Did we already visit Z. No! we didn't
route(Z,B,[Z|Been],ZtoB). %Log city Z and look for a root from Z to B
这不是最优的:一旦访问城市a在一条路径上失败,如果您选择另一条路径到该城市,它也会失败。您可以使用non-bactrackable store 来维护您访问过的城市列表,以便将其转换为O(n 2 )算法。实施取决于方言。