Path 在Prolog中查找图形中所有可能的不带循环的路径
我有一个逻辑课的家庭作业,但或多或少都不知道如何解决它。。。 用这样的疑问Path 在Prolog中查找图形中所有可能的不带循环的路径,path,prolog,find,graph-theory,Path,Prolog,Find,Graph Theory,我有一个逻辑课的家庭作业,但或多或少都不知道如何解决它。。。 用这样的疑问 ?- find(a,[r(a,[b,d]),r(b,[a,c,e]),r(c,[b]),r(d,[a,e]), r(e,[b,d,f]),r(f,[e,g]),r(g,[f])],Path). Prolog应该返回给定图形中所有可能的路径。术语r(X,List)定义了图形,这意味着可以从节点X访问列表中的节点。在这种情况下,输出为: Path = [a,b,c] ; Path = [a,b,e,d] ; Pat
?- find(a,[r(a,[b,d]),r(b,[a,c,e]),r(c,[b]),r(d,[a,e]),
r(e,[b,d,f]),r(f,[e,g]),r(g,[f])],Path).
Prolog应该返回给定图形中所有可能的路径。术语r(X,List)定义了图形,这意味着可以从节点X访问列表中的节点。在这种情况下,输出为:
Path = [a,b,c] ;
Path = [a,b,e,d] ;
Path = [a,b,e,f,g] ;
Path = [a,d,e,b,c] ;
Path = [a,d,e,f,g] ;
false.
虽然我在SE和web上掌握了许多解决类似问题的方法,但不知何故,我太笨了,不知道如何在本作业中使用图形的定义
我认为find(Start,…)应该与r(Start,list)中列表的所有成员一起递归调用,但是作为Prolog的新手(我们刚刚做了标准的家谱…),我不知道怎么做
任何帮助都将不胜感激。我知道我没有太多的开始,但我已经花了半个晚上试图弄明白一些事情,到目前为止我一点线索也没有
/编辑:
首先,我想我需要一些基本情况来中止递归。
我认为两者都应该
find([],_,_).
因为我猜最后一个递归调用没有任何开始,或者
find(_,[],_).
假设定义相邻节点的术语列表在程序完成处理时应为空
现在是实际通话。大概是
find(Start,[r(Start,[Adjacent|Restadj])|Rest],Path):-
find(???).
我的问题如下:
-如何使程序使用r(…)术语中的列表成员作为下一个开始
-如何检查节点是否已被“访问”/如何从r中的特定列表中删除节点
-如何将找到的节点放入路径列表中?简单地附加?或者使用类似于[Path | Start]的方法执行递归调用
如你所见,这并不多。一些有启发性的问题会很好,因为序言看起来很有趣,所以学习起来很有趣
在花了一些时间使用整洁的PDT Eclipse跟踪工具之后,我想我理解了该程序正在做什么。我现在不明白的是为什么最后一个节点总是丢失。回溯失败后,例如,因为r(c,[b])是下一个找到的项,而memberchk(b,[b])由于否定而失败(这就是I thing+所做的),并且找不到其他与r(c,X)相关的项,所以它开始寻找从节点b出发的其他可能性,该节点b在r(b,[…])中留下了相邻的节点。但是为什么程序忘记将节点c放入路径列表中呢?有没有可能在这种情况下做一些if-then-else
member(r(Node, Adjacent), Graph),
member(AdjNode, Adjacent),
\+ memberchk(AdjNode, Seen),
失败,是否仍将最后一个节点附加到路径?我怀疑让您感到困惑的是,您必须从显式数据结构中查找数据,而不是从数据库中获取数据。第一条裂缝可能如下所示:
find(_, _, []).
find(Node, Graph, [Node|Path]) :-
member(r(Node,Adjacent), Graph),
member(AdjNode, Adjacent),
find(AdjNode, Graph, Path).
查看我如何使用member/2
从图中查找数据。但是这个解决方案是不正确的,因为它是循环的。一个改进可能是:
find(Node, Graph, Path) :- find(Node, Graph, Path, []).
find(_, _, [], _).
find(Node, Graph, [Node|Path], Seen) :-
member(r(Node, Adjacent), Graph),
member(AdjNode, Adjacent),
\+ memberchk(AdjNode, Seen),
find(AdjNode, Graph, Path, [Node|Seen]).
这个版本基本上与上面的版本相同,只是它有一个“已看到”列表来跟踪它已经到达的位置。这仍然不能产生您想要的输出,但我认为这足以让您走上正确的轨道
编辑响应您的编辑
首先,我想我需要一些基本情况来中止递归
对。我选择第一种情况是因为我认为在遍历过程中不能安全地“使用”图形。我想您可以使用select/3
代替member/2
并在不使用此节点的情况下向前传递图形。这可能是一个有趣的尝试(建议!)
- 如何使程序使用r(…)术语中的列表成员作为下一个开始
member/2
从图形中检索内容。这很有趣,因为您使用了与所需谓词完全相同的单词。:)
- 如何检查节点是否已被“访问”/如何从r中的特定列表中删除节点
memberchk/3
或member/3
- 如何将找到的节点放入路径列表中?简单地附加?或者使用类似于[Path | Start]的方法执行递归调用
findall/3
,我们可以一次找到所有路径:
all_paths(From, Graph, Paths) :- findall(Path, find(From, Graph, Path), Paths).
您可以这样调用它:
?- all_paths(a, [r(a,[b,d]),r(b,[a,c,e]),r(c,[b]),r(d,[a,e]),
r(e,[b,d,f]),r(f,[e,g]),r(g,[f])], AllPaths).
我还没有测试过,但它应该可以工作。基于Daniel Lyons的清晰代码,广度优先搜索:
所有路径(节点、图形、路径):-
bfs(图,[[Node]-[]],R,[]),%或dfs(…)
映射列表(fst、路径、R)。
fst(A,A-)效用
对(B,A,A-B)。%助手
加(LS,H[H|LS])。%
bfs(_G,[],Z,Z)。%队列为空
bfs(图[H | Q],[H | R],Z):-
H=看到的路径,路径=[Node | U3;],
findall(Next,member(r(Node,Next),Graph),NS,
展平_diff(NS,Seen,WS),%节点工作集
映射列表(添加(路径)、WS、PS),%新路径
映射列表(对([Node | Seen])、PS、QH、%新添加到队列
%%追加(QH,Q,Q2),%DFS
附加(Q、QH、Q2),%BFS
bfs(图,Q2,R,Z)。
(未经测试)<代码>展平差异(A、B、C)应展平列表A
,同时删除列表B
中出现的元素,从而生成列表C
正如PeterPanter所注意到的,Daniel Lyons的代码需要稍微调整,以不排除其结果路径中的最后一个节点
find(节点,图形,[Node | Path]):-find(节点,图形,路径,[])。
查找(u,u,[],u)。
查找(节点,图形,[AdjNode |路径],已看到):-
成员(r(节点,相邻),图),
M