在循环图prolog中反向搜索

在循环图prolog中反向搜索,prolog,Prolog,我有一个prolog程序的问题,因为我是一个完全的初学者,所以我想我来这里寻求一些答案或帮助 这是我的数据库: road(hoor,horby). road(horby,lund). road(horby,sjobo). road(lund,sjobo). road(sjobo,tomelilla). road(sjobo,ystad). road(tomelilla,ystad). road(ronne,gudhjem). 那么我的规则是: :- op(150, xfy, to). X t

我有一个prolog程序的问题,因为我是一个完全的初学者,所以我想我来这里寻求一些答案或帮助

这是我的数据库:

road(hoor,horby).
road(horby,lund).
road(horby,sjobo).
road(lund,sjobo).
road(sjobo,tomelilla).
road(sjobo,ystad).
road(tomelilla,ystad).
road(ronne,gudhjem).
那么我的规则是:

:- op(150, xfy, to).

X to Y :-
    findall(Waypoint, get_waypoints(X,Y,Waypoint), Waypoints),
    write(Waypoints).

get_waypoints(Start, End, []) :- 
    road(Start, End).
get_waypoints(Start, End, [Waypoint|Result]) :-
    road(Start, Waypoint),
    get_waypoints(Waypoint, End, Result).
例如,当我询问时,它工作正常

?- horby to ystad.
然后,输出变为:

[[lund,sjobo],[lund,sjobo,tomelilla],[sjobo],[sjobo,tomelilla]]
true.
这是完美的。但假设我想找到从?-伊斯塔德到霍比的路。 当我问这个问题时,它只会给我:

[]
true.
我可以采用哪些方法来解决此问题?
提前谢谢你

使用双向道路

问题是你的道路是单向的。你需要双向使用它们

您可以通过添加新规则来完成此操作:

connected(X, Y):- road(X, Y) ; road(Y, X).
现在,如果您只是将
道路(起点,航路点)
替换为
已连接(起点,航路点)
,您现在可以在所有方向上搜索,但是您的谓词
get_航路点
将产生无限多的解决方案,因为它可能在城市之间来回移动

检查某个城市是否已被访问

你需要检查你所访问的城市以前是否没有人去过。您可以使用到目前为止访问过的城市列表(累加器)来完成此操作:

get_waypoints(Start, End, Waypoints):-
    get_waypoints(Start, End, [Start], Waypoints).

get_waypoints(Current, End, Acc, Waypoints):-
    connected(Current, End),
    reverse(Acc, [_|Waypoints]).

get_waypoints(Current, End, Acc, Waypoints):-
    connected(Current, Waypoint),
    Waypoint \== End,
    \+ member(Waypoint, Acc),
    get_waypoints(Waypoint, End, [Waypoint|Acc], Waypoints).
子目标
航路点\==End
确保一旦到达目的地,就不会在该路径上进一步构建<代码>\+会员(航路点,Acc)确保您不会两次访问同一城市

因为你需要检查你是否没有返回出发城市,累加器也会包含它。也就是说,最后,当累加器反转时,第一个元素(起始城市)被丢弃:
reverse(Acc,[\u124;航路点])

示例查询

| ?- ystad to horby.
[[sjobo],[sjobo,lund],[tomelilla,sjobo],[tomelilla,sjobo,lund]]

yes
更新:在结果列表中包括开始和结束节点(在注释中请求)

要将起始城市和结束城市与航路点一起包含在结果中,只需将
end
节点添加到
get\u航路点/2
的第一条规则中的累加器中即可:

get_waypoints(Current, End, Acc, Waypoints):-
    connected(Current, End),
    reverse([End|Acc], Waypoints]).

简而言之,如果你有一条从
X
Y
的路,那么,隐含地说,你有一条从
Y
X
的路,但是你的Prolog规则不知道这一点。您可以将对称性添加到Prolog代码中,但需要注意循环路由。小调:不要将自己的运算符定义为起始运算符。您能证明标记的合理性吗?从问题的描述来看,这似乎是一个简单的循环,而不是一个哈密顿回路。非常感谢你!这非常有效,我非常感激你的回答!我有一个关于
反转的问题。当到达
reverse
时,它的Acc为
[horby,hoor]
,并将
航路点设置为
horboy
,请您详细解释一下它的功能。当我使用调试器时,我很难理解它。非常感谢。累加器有两个功能角色:(1)迭代构建解决方案(开始节点和结束节点之间的中间节点);(2) 包含已访问的节点列表(这样可以避免多次访问同一城市)。对于第一个目标,您不需要起始节点,但对于第二个目标,您需要。现在,累加器以相反的顺序包含访问的节点。到达目标节点时,需要:(1)反转累加器;(2) 放弃起始节点(现在它成为反向累加器的头部)。在您的情况下,您从
hoor
开始,通过
horby
到达目的地(不知道是哪个)。因此,累加器是
[horby,hoor]
,包含起始节点和航路点。首先,您将其反转,以按访问顺序获取城市:
[hoor,horby]
。由于第一个元素,
hoor
是起始节点,您不需要它,因此您只需要该列表的尾部:
[horby]
(仅指航路点)。现在这对我来说更有意义了!再次感谢你的帮助,你在短时间内为我节省了很多时间,也给了我很多知识!