在图中循环检测

时间:2011-07-17 00:21:25

标签: prolog directed-graph

我们给出了一个包含以下事实的图表:

edge(a,b)
edge(a,c)
edge(b,a)
edge(c,d)
edge(d,d)
edge(d,e)
edge(e,f)
edge(f,g)
edge(g,e)

我们被要求定义一个规则cycle(X),用于确定是否存在从节点X开始的循环。

我真的迷失了如何做到这一点,我试图遍历节点并检查下一个节点是否会再次成为起始节点,但我似乎无法让它工作

6 个答案:

答案 0 :(得分:4)

Archie的想法是一个很好的起点,但如果在搜索路径时发现另一个循环,它将创建一个无限循环。

我也没有多年使用过prolog,但你需要像path(X,Y,Visited)这样的东西,你可以跟踪被访问的节点,防止无限循环。

答案 1 :(得分:3)

如果我们在遍历期间遇到任何被访问节点,则它使用深度优先搜索和访问节点列表返回true。我用小输入测试它看起来像是正常工作。

cycle(X):- cycleh(X,[X]).
cycleh(X,Visited) :- edge(X,Y), (member(Y,Visited) -> !,true; cycleh(Y,[Y|Visited])).

答案 2 :(得分:2)

这应该可以解决问题:

cycle( X ) :-
  cycle( X , [] ).

cycle( Curr , Visited ) :-
  member( Curr, Visited ) ,
  !. 
cycle( Curr , Visited ) :-
  edge( Curr , Next ) ,
  cycle( Next , [Curr|Visited] ) .

虽然它似乎是与@GökhanUras类似的解决方案 - 伟大的思想家也一样!或者是什么B ^)

基本逻辑是,如果当前节点已被访问,则有一个循环(cycle/2辅助谓词中的第一个子句。此时,我们剪切(!)并声明成功的原因cut(!)就是没有它,回溯将导致重新访问已经访问过的节点,从而产生一组无限的循环。

如果尚未访问当前节点,我们抓住锚定在当前节点的边缘并访问该节点。回溯到cycle/2的第2个子句会访问下一个边缘,因此一旦特定路径耗尽,cycle/2就会回溯并尝试另一条路径。

答案 3 :(得分:1)

如果你的Prolog系统有一个正向链接器,你可以用它来确定周期。但请注意,它可能会占用相当多的记忆,因为它会生成并保留path/2个事实。

以下是您需要如何在正向链接器中制定不会自动删除重复的规则。 \+用于明确消除重复项:

:- forward edge/2.
:- forward path/2.

path(X,Y) :- edge(X,Y), \+ path(X,Y).
path(X,Y) :- edge(X,Z), path(Z,Y), \+ path(X,Y).
cycle(X) :- path(X,X).

为了使示例更有趣,结果是什么,我放弃了edge(d,d)。这是一个示例运行:

?- postulate(edge(a,b)), postulate(edge(a,c)), postulate(edge(b,a)),    
postulate(edge(c,d)), postulate(edge(d,e)), postulate(edge(e,f)), 
postulate(edge(f,g)), postulate(edge(g,e)), cycle(X).
X = a ;
X = b ;
X = e ;
X = f ;
X = g

postulate/1谓词在这里发布一个事件并保持正向链接的传播者运行。如何编写前向规则取决于您正在使用的Prolog系统各自的库。

P.S。:还有一些研究正在进行:
http://x10.sourceforge.net/documentation/papers/X10Workshop2011/elton_slides.pdf

答案 4 :(得分:0)

我使用Prolog已经有一段时间了,但也许这种方法可行:路径是一系列边缘,其中每条边都在前一边缘结束的节点上开始(例如a - &gt ; b,b - > c,c - > d)。平凡路径是单个边缘,通过采用现有路径并向其添加边缘,可以形成更复杂的路径。循环是在同一节点上开始和结束的路径。您可以使用这些定义来构建Prolog规则吗?

答案 5 :(得分:-1)

我有一段时间没有使用Prolog,但这是解决这个问题的方法。

您可以制定规则path(X,Y),检查是否存在从节点XY的路径。路径是单个边缘或通向路径的边缘。有了这个,很容易找到从节点X开始的循环 - 它只是path(X,X)。这是我的实现(取自我的头脑,不一定正确,但给出了想法):

path(X,Y) :- edge(X,Y).
path(X,Y) :- edge(X,Z), path(Z,Y).

cycle(X) :- path(X,X).