我的逻辑课程有一个家庭作业,但或多或少不知道如何解决它......用一个像这样的查询
?- 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 到达 List 中的节点。在这种情况下,输出将是:
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] 之类的东西执行递归调用?
如您所见,这并不多。一些暗示性的问题会很好,因为 Prolog 看起来很有趣,因此学习起来很有趣......
在使用了简洁的 PDT-Eclipse 跟踪工具一段时间后,我想我理解了程序在做什么。我现在不明白的是为什么最后一个节点总是会丢失。回溯失败后,例如因为 r(c,[b]) 是下一个找到的术语,而 memberchk(b,[b]) 由于否定(这就是我所做的事情)而失败,并且没有其他术语 r(c ,X) 可以找到,它开始寻找从节点 b 出发的其他可能性,节点 b 在 r(b,[...]) 中留下了相邻的节点。但是为什么程序忘记将节点 c 放入 Path 列表中呢?是否有可能做某种 if-then-else 以防万一
member(r(Node, Adjacent), Graph),
member(AdjNode, Adjacent),
\+ memberchk(AdjNode, Seen),
失败,仍然将最后一个节点附加到路径?