使用列表从本地堆栈中prolog

使用列表从本地堆栈中prolog,prolog,transitive-closure,Prolog,Transitive Closure,我必须找到两个州之间的路线,我到了这里,到现在为止,关于堆栈外的帮助我,我有一个错误 % state 1 is border of state 2 % borders(A , B). borders(sasktchewan, alberta). borders(saskatchewan, manitoba). borders(saskatchewan, nwt). borders(alberta, british_columbia). borders(alberta, saskatchewan

我必须找到两个州之间的路线,我到了这里,到现在为止,关于堆栈外的帮助我,我有一个错误

% state 1 is border of state 2
% borders(A , B). 
borders(sasktchewan, alberta).
borders(saskatchewan, manitoba).
borders(saskatchewan, nwt).
borders(alberta, british_columbia).
borders(alberta, saskatchewan).
borders(alberta, nwt).
borders(british_coumbia, yukon).
borders(british_coumbia, nwt).
borders(british_coumbia, alberta).
borders(nwt, saskatchewan).
borders(nwt, alberta).
borders(nwt, british_columbia).
borders(nwt, yukon).
borders(nwt, manitoba).
borders(manitoba, saskatchewan).
borders(manitoba, nwt).

route( A, B, [ go(A,B) ] ) :-   borders( A, B ). 
route( A, B, [ go(A,Z) | ZtoB ] ) :-   borders( A, Z ),   route( Z, B, ZtoB ).

问题是你没有把你已经去过的地方记账。现在假设您希望从萨斯克彻温省转到马尼托巴省。Prolog将对此进行评估,如下所示:

(sasktchewan) <--------------
 `--(alberta)                \
     `--(british_columbia)   |
        |--(yukon) fail!     |
        `--(nwt)             |
           `-(sasktchewan)---/
你需要做的是使用一个累加器,列出你已经去过的所有地方。从您访问该城市的那一刻起,每次进行会员检查时,您都会中断。因此:

%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城市的访问在一条路径上失败,如果您选择另一条路径访问该城市,它也将失败。您可以使用商店维护您访问过的城市列表,以便将其转换为O(n2)算法。实现取决于方言。

显示您输入的导致堆栈溢出的示例查询。它在
路径上无限递归
。如果执行
跟踪
,则可以看到是哪些参数导致了这种情况。但总的来说,这意味着你在路上“兜圈子”。解决这个问题的一种方法是跟踪您在附加参数中的位置,并检查您是否已经在那里(使用
member
)。这里有一个例子,但同样的原则也适用。
%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