List 从Prolog中具有相邻元素的列表中查找所有可能的路径?

List 从Prolog中具有相邻元素的列表中查找所有可能的路径?,list,recursion,path,prolog,List,Recursion,Path,Prolog,我为这个尴尬的标题提前道歉,因为它有点难以用几句话来表达清楚 目标是根据输入房间找到从一个房间到另一个房间的所有可能路径和总能量。所以这个列表[r1,r2,3]意味着你可以从1号房间到2号房间,从2号房间到1号房间,这两种方式都需要3个能量。您不允许前往以前去过的房间 以下是代表哪些房间也可以旅行的列表列表 adjacent([[r1,r2,8],[r1,r3,2],[r1,r4,4],[r2,r3,7],[r3,r4,1],[r2,r5,2],[r4,r6,5],[r6,r3,9],[r3,r

我为这个尴尬的标题提前道歉,因为它有点难以用几句话来表达清楚

目标是根据输入房间找到从一个房间到另一个房间的所有可能路径和总能量。所以这个列表[r1,r2,3]意味着你可以从1号房间到2号房间,从2号房间到1号房间,这两种方式都需要3个能量。您不允许前往以前去过的房间

以下是代表哪些房间也可以旅行的列表列表

adjacent([[r1,r2,8],[r1,r3,2],[r1,r4,4],[r2,r3,7],[r3,r4,1],[r2,r5,2],[r4,r6,5],[r6,r3,9],[r3,r5,3]]). 
这是我的代码,它确实正确地找到了路径,但是所有未来可能的路径都只是重复前面的房间,因为我不确定如何实现该功能。我想我可以简单地使用不memberPosPath,因为路径包含了所有之前移动到元素的列表,但它似乎在之前的某个时间将PosPath添加到路径中,所以它总是失败

trip(Start,End,[Start,End],Energy):- adjacent(List), member([Start,End,Energy],List).

trip(Start,End,[Start|Paths],TotalE) :- 
                    adjacent(List),
                    member([Start,PosPath,E], List),
                    % not member(PosPath, Paths),
                    trip(PosPath,End,Paths,PathE).
                    % TotalE is E+PathE.
输出:

?- trip(r1, r6, Path, TotalE).
Path = [r1, r2, r3, r4, r6]
Total = Total
Yes (0.00s cpu, solution 1, maybe more)
Path = [r1, r2, r3, r4, r6, r3, r4, r6]
Total = Total
Yes (0.00s cpu, solution 2, maybe more)
Path = [r1, r2, r3, r4, r6, r3, r4, r6, r3, r4, r6]
TotalE = TotalE
Yes (0.00s cpu, solution 3, maybe more)
由于[r1,r2,3]中的房间表示一条双向路径,我建议使用一个谓词来描述这种对称性,我们将其称为从_到_cost/3:

from_to_cost(X,Y,C) :-
   adjacent(L),
   member([X,Y,C],L).
from_to_cost(X,Y,C) :-
   adjacent(L),
   member([Y,X,C],L).
对于调用谓词,我建议使用一个更具描述性的名称,比如start\u end\u path\u cost/4,它对应于谓词trip/4。对于描述实际关系的谓词,还需要两个附加参数:一个累加器,用于汇总从0开始的路径成本;一个访问房间列表,以第一个房间作为单个元素开始:

实际关系必须描述两种情况:

1如果起始房间和结束房间相等,则找到路径。然后,成本和累加器也相等,路径为空

2否则,有一个尚未访问的中介室,可以通过S:

现在,您的示例查询将查找所有解决方案并终止:

?- start_end_path_cost(r1, r6, Path, TotalE).
Path = [r2, r3, r4, r6],
TotalE = 21 ;
Path = [r2, r3, r6],
TotalE = 24 ;
Path = [r2, r5, r3, r4, r6],
TotalE = 19 ;
Path = [r2, r5, r3, r6],
TotalE = 22 ;
Path = [r3, r4, r6],
TotalE = 8 ;
Path = [r3, r6],
TotalE = 11 ;
Path = [r4, r6],
TotalE = 9 ;
Path = [r4, r3, r6],
TotalE = 14 ;
false.
最一般的查询将查找给定连接的所有137个解决方案,并终止:

?- start_end_path_cost(S, E, Path, TotalE).
S = E,
Path = [],
TotalE = 0 ;
S = r1,
E = r2,
Path = [r2],
TotalE = 8 ;
S = r1,
E = r3,
Path = [r2, r3],
TotalE = 15 ;
.
.
.
S = r5,
E = r1,
Path = [r3, r6, r4, r1],
TotalE = 21 ;
S = r5,
E = r2,
Path = [r3, r6, r4, r1, r2],
TotalE = 29 ;
false.
编辑: 关于你在评论中的问题:是的,这是可能的。您可以定义一个谓词,该谓词将第一个参数描述为不是第二个参数列表的元素,我们称之为nonmember/2:

nonmember(_A,[]).
nonmember(A,[H|T]):-
   dif(A,H),
   nonmember(A,T).
然后可以将s_e_p_c_/6中的映射列表目标替换为nonmember/2,如下所示:

s_e_p_c_(E,E,[],C,C,_Visited).
s_e_p_c_(S,E,[X|Path],C,C0,Visited) :-
   nonmember(X,Visited),                  % <- here
   from_to_cost(S,X,SXC),
   C1 is C0+SXC,
   s_e_p_c_(X,E,Path,C,C1,[X|Visited]).

通过此更改,查询将产生相同的结果。

在没有maplist/2谓词的情况下,是否仍可以实现此操作?
nonmember(_A,[]).
nonmember(A,[H|T]):-
   dif(A,H),
   nonmember(A,T).
s_e_p_c_(E,E,[],C,C,_Visited).
s_e_p_c_(S,E,[X|Path],C,C0,Visited) :-
   nonmember(X,Visited),                  % <- here
   from_to_cost(S,X,SXC),
   C1 is C0+SXC,
   s_e_p_c_(X,E,Path,C,C1,[X|Visited]).