我提前为这个尴尬的标题道歉,因为有点难以清楚地说几句话。
目标是找到所有可能的路径以及从一个房间使用的总能量"另一个基于输入房间。所以列表[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]]).
这是我的代码,它正确地找到了一个路径,但是所有未来可能的路径只是重复以前的房间,因为我不确定如何实现该功能。我想我可以简单地使用not member(PosPath,Paths),因为Paths保存了以前所有传递给元素的列表,但似乎事先将PosPath添加到Paths所以它总是失败。
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)
答案 0 :(得分:1)
由于[r1,r2,3]
中的房间代表双向路径,我建议使用描述这种对称性的谓词,让我们将其称为from_to_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_end_path_cost / 4,它对应于你的谓词trip / 4。对于描述实际关系的谓词,需要两个额外的参数:累加器来总结路径的成本,从0
开始,以及以第一个房间作为单个元素开始的访问房间列表{ {1}}:
[S]
实际关系必须描述两种情况:
1)如果起始房间和终端房间相等,则找到路径。然后成本和累加器也是相等的,路径是空的。
2)否则,有一个尚未访问过的中间房间,可以从start_end_path_cost(S,E,P,C) :-
s_e_p_c_(S,E,P,C,0,[S]).
到达:
S
现在,您的示例查询找到所有解决方案并终止:
s_e_p_c_(E,E,[],C,C,_Visited).
s_e_p_c_(S,E,[X|Path],C,C0,Visited) :-
maplist(dif(X),Visited),
from_to_cost(S,X,SXC),
C1 is C0+SXC,
s_e_p_c_(X,E,Path,C,C1,[X|Visited]).
最常见的查询会查找给定连接的所有137个解决方案并终止:
?- 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.
关于你在评论中的问题:是的,这是可能的。您可以定义一个谓词,该谓词描述第一个参数不是列表中第二个参数的元素,让我们将其称为非成员/ 2:
?- 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.
然后你可以用非成员/ 2替换s_e_p_c_ / 6中的地图列表目标,如下所示:
nonmember(_A,[]).
nonmember(A,[H|T]):-
dif(A,H),
nonmember(A,T).
通过此更改,查询会产生相同的结果。