List 打印图形的指定节点Prolog的所有图形周期
我是序言世界的新手。我正在尝试编写谓词,以便为图形的指定节点(即给定节点的元素)打印图形的所有周期。我的图表是这样的List 打印图形的指定节点Prolog的所有图形周期,list,prolog,graph-theory,cycle,transitive-closure,List,Prolog,Graph Theory,Cycle,Transitive Closure,我是序言世界的新手。我正在尝试编写谓词,以便为图形的指定节点(即给定节点的元素)打印图形的所有周期。我的图表是这样的 edge(a,e). edge(e,d). edge(d,c). edge(c,b). edge(b,a). edge(d,a). edge(e,c). edge(f,b). cycle(X) :- cycle(X, []). cycle(Curr, Visited) :- member(Curr, Visited), !. cycle(Curr, V
edge(a,e).
edge(e,d).
edge(d,c).
edge(c,b).
edge(b,a).
edge(d,a).
edge(e,c).
edge(f,b).
cycle(X) :-
cycle(X, []).
cycle(Curr, Visited) :-
member(Curr, Visited),
!.
cycle(Curr, Visited) :-
edge(Curr, Next),
cycle(Next, [Curr|Visited]).
不幸的是,现在我找不到特定节点的循环。例如,我正在查找node
d
的所有周期,我认为问题在于您根本没有编写任何逻辑来返回周期
源于节点的循环
这并不难,您已经使用了一个累加器,您只需要一个机制,一旦找到循环,就将累加器作为循环返回。您可以通过向循环提供一个附加参数来完成此操作:
cycle(Node,Cycle) :-
cycle(Node,[],Cycle).
cycle(Curr,Visited,Cycle) :-
member(Curr,Visited),
!,
reverse([Curr|Visited],Cycle).
cycle(Curr,Visited,Cycle) :-
edge(Curr,Next),
cycle(Next,[Curr|Visited],Cycle).
在这个实现中,我使用了reverse/2
,因为这将为您提供正确的节点顺序(沿边)。如果您对此不感兴趣(例如,您只希望分析周期,您可以以相反的方式进行分析,您可以简单地将cycle/3
的第一个子句中的cycle
替换为[Curr | visted]
但问题是,如果调用此谓词,它将返回:
?- cycle(d,Cycle).
Cycle = [d, c, b, a, e, d] ;
Cycle = [d, c, b, a, e, c] ;
Cycle = [d, a, e, d] ;
Cycle = [d, a, e, c, b, a].
因此,它不会搜索周期,而d
本身就是周期的一部分,它会搜索所有可以源自d
的周期。这可能不是您想要的
具有给定节点的循环
但是,您可以重写谓词:您需要存储您发起的节点:
cycle(Node,Cycle) :-
edge(Node,Next),
cycle(Node,Next,[Node],Cycle).
因此,我们在这里查找源自节点的每个边缘/2
,并调用循环/4
,使用初始节点(在找到循环时进行检查),下一个节点,访问的[Node]
列表和循环参数返回找到的循环
现在,循环/4有三个可能的选项:
- 我们到达原始节点,在这种情况下,我们找到了一个循环,
节点
是其中的一部分,我们进行的处理与第一个版本类似:
cycle(Curr,Curr,Visited,Cycle) :-
!,
reverse([Curr|Visited],Cycle).
- 我们到达一个已经访问过的节点:
Curr
是已访问
的一个元素,在这种情况下,我们需要中断搜索:否则我们将循环无限次:
cycle(_,Curr,Visited,_) :-
member(Curr,Visited),
!,
fail.
fail
是一个声明分支失败的谓词。这可能很有用,因为现在我们指定它如何失败
- 最后,我们只需访问另一个边缘并尝试查找下一个节点:
cycle(Node,Curr,Visited,Cycle) :-
edge(Curr,Next),
cycle(Node,Next,[Curr|Visited],Cycle).
全文如下:
cycle(Node,Cycle) :-
edge(Node,Next),
cycle(Node,Next,[Node],Cycle).
cycle(Curr,Curr,Visited,Cycle) :-
!,
reverse([Curr|Visited],Cycle).
cycle(_,Curr,Visited,_) :-
member(Curr,Visited),
!,
fail.
cycle(Node,Curr,Visited,Cycle) :-
edge(Curr,Next),
cycle(Node,Next,[Curr|Visited],Cycle).
由此产生:
?- cycle(d,Cycle).
Cycle = [d, c, b, a, e, d] ;
Cycle = [d, a, e, d] ;
因此,所有这些都是从d
开始的循环,然后再次访问d
。我们可以通过将第二个和第三个场景压缩到一个子句中来提高代码的效率:
cycle(Node,Cycle) :-
edge(Node,Next),
cycle(Node,Next,[Node],Cycle).
cycle(Curr,Curr,Visited,Cycle) :-
!,
reverse([Curr|Visited],Cycle).
cycle(Node,Curr,Visited,Cycle) :-
\+ member(Curr,Visited),
edge(Curr,Next),
cycle(Node,Next,[Curr|Visited],Cycle).
其中\+
的意思不是。我觉得你在寻找什么……不需要重新发明轮子
只需基于“”中所示的经过测试的代码进行构建,并定义:
in_cycle(R_2, AZ, Path) :- % cf. "simple cycle"
First = AZ,
Last = AZ,
path(R_2, Path, First, ButLast), % all "hops" but the last one ...
call(R_2, ButLast, Last). % ... and here comes the last one
查询#1的所有解决方案也满足了更一般的查询#2单调序言,在工作中:)谢谢威廉,我真的很感激你的回答,它对我帮助很大。现在我完全明白了。谢谢
| ?- in_cycle(edge, d, Path).
Path = [d,c,b,a,e] ? ;
Path = [d,a,e] ? ;
no
| ?- in_cycle(symm(edge), d, Path).
Path = [d,c] ? ;
Path = [d,c,b,a] ? ;
Path = [d,c,b,a,e] ? ;
Path = [d,c,e] ? ;
Path = [d,c,e,a] ? ;
Path = [d,a] ? ;
Path = [d,a,e] ? ;
Path = [d,a,e,c] ? ;
Path = [d,a,b,c] ? ;
Path = [d,a,b,c,e] ? ;
Path = [d,e] ? ;
Path = [d,e,c] ? ;
Path = [d,e,c,b,a] ? ;
Path = [d,e,a] ? ;
Path = [d,e,a,b,c] ? ;
no