如果我有一个边缘列表,比如"告诉我从一个被认为危险的城市到一个被认为安全的城市的路线",这样......
dangerous(oakland).
safe(portland).
move(rome,plane,portland).
move(portland,plane,rome).
move(halifax,train,gatwick).
move(gatwick,car,rome).
move(portland,plane,newyork).
move(oakland,plane,rome).
move(oakland,plane,gatwick).
move(halifax,train,gatwick).
move(gatwick,plane,rome).
move(oakland,train,newyork).
我可以使用以下深度优先搜索(在 SO 上找到)获得通往安全城市的路径列表......
dfs_start(Start, Goal, Path) :- phrase(dfs(Start, [], Goal), Path).
dfs(Node, _, Goal) --> [Node], { call(Goal, Node) }.
dfs(Node0, Es, Goal) --> [Node0],
{ move(Node0,_,Node1), + member(Node1, Es) },
dfs(Node1, [Node0|Es], Goal).
然而,我试图解决的问题是找到所有来自危险城市的路径,这些路径不通向一个安全的城市(在这种情况下,只有一个奥克兰 ->纽约)。如果我用...
dfs_start(oakland,safe,Path).
。我得到
Path = [oakland, rome, portland] ;
Path = [oakland, gatwick, rome, portland] ;
Path = [oakland, gatwick, rome, portland] ;
。但我想做的是称呼类似的东西...
dfs_start(oakland,unsafe,Path).
。并得到...
Path = [oakland, newyork] ;
任何建议将不胜感激!
问题描述模棱两可,也许这就是您怀疑的原因。据我了解,unsafe(X).
显然是错误的,因为消除了每个过滤条件。您可以尝试以这种方式简化规则(我已经注释掉了低效的规则,您可以删除它):
% unsafe(X) :- findall(Y,safe(Y),SafeList), member(X,SafeList), !, fail.
unsafe(X) :- + safe(X).
编辑你与威尔·尼斯交换的评论澄清了一点任务:当路径不能再延伸时,停止条件必须为真,任何安全的城市都被禁止路径。我简化了一些代码,删除了不必要的功能,因此您可以专注于逻辑:graph 是非循环的,因此不需要访问路径,而不是传递 Goal,只需使用 required 语句:
unsafe_path([Start|Path]) :-
dangerous(Start),
phrase(dfs(Start), Path).
dfs(Node) --> [Node1],
{ move(Node, _, Node1),
+ lead_to_safe(Node1)
} -> dfs(Node1) ; {true}.
lead_to_safe(Node) :- safe(Node).
lead_to_safe(Node) :-
move(Node, _, Node1),
lead_to_safe(Node1).
测试:
?- unsafe_path(P).
P = [oakland, newyork].
如果我们添加一个虚构的城市,路径会延伸:
?- assertz(move(newyork,train,turin)).
?- unsafe_path(P).
P = [oakland, newyork, turin].
如果我们让都灵成为通往安全城市的门户:
?- assertz(move(turin,train,portland)).
?- unsafe_path(P).
P = [oakland].