【问题标题】:Print all cycles of the graph for the specified node of the graph, Prolog为图形的指定节点打印图形的所有循环,Prolog
【发布时间】:2016-01-14 18:05:30
【问题描述】:

我是 Prolog 世界的新手。我正在尝试编写谓词来打印图形的指定节点的所有循环,这是给定节点的元素。我的图表是这样的。

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]).

不幸的是,现在我找不到特定节点的循环。例如,我正在寻找节点 d 的所有周期。

【问题讨论】:

    标签: list prolog graph-theory cycle


    【解决方案1】:

    在我看来,您正在寻找的内容类似于 ...无需重新发明轮子!

    只需构建在“Definition of a path/trail/walk”中显示的久经考验的代码并定义:

    in_cycle(R_2,AZ,路径):- % cf。 “simple cycle” 首先 = AZ, 最后 = AZ, path(R_2, Path, First, ButLast), % 所有“跃点”,但最后一个... call(R_2, ButLast, Last)。 % ...最后一个来了

    使用SICStus Prolog 4.3.2 的示例查询#1:

    | ?- in_cycle(edge, d, Path)。 路径 = [d,c,b,a,e] ? ; 路径 = [d,a,e] ? ; 不

    在示例查询 #2 中,我们查看edge/2symmetric closure 的传递闭包:

    | ?- in_cycle(symm(edge), d, 路径)。 路径 = [d,c] ? ; 路径 = [d,c,b,a] ? ; 路径 = [d,c,b,a,e] ? ; 路径 = [d,c,e] ? ; 路径 = [d,c,e,a] ? ; 路径 = [d,a] ? ; 路径 = [d,a,e] ? ; 路径 = [d,a,e,c] ? ; 路径 = [d,a,b,c] ? ; 路径 = [d,a,b,c,e] ? ; 路径 = [d,e] ? ; 路径 = [d,e,c] ? ; 路径 = [d,e,c,b,a] ? ; 路径 = [d,e,a] ? ; 路径 = [d,e,a,b,c] ? ; 不

    查询#1的所有解决方案满足更一般的查询#2-单调Prolog1,2,3在工作:)

    【讨论】:

      【解决方案2】:

      我认为问题在于您只是没有编写任何逻辑来返回循环

      源自节点的循环

      这并不难,您已经使用了一个累加器,您只需要一种机制,一旦找到循环,就将您的累加器作为循环返回。您可以通过向cycle 提供一个附加参数来做到这一点:

      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|Visited]

      然而问题是,如果你调用这个谓词,它会返回:

      ?- 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).
      

      所以在这里我们查找每个源自Nodeedge/2 并使用初始Node 调用cycle/4(以检查我们何时找到一个循环),Next 节点,访问的列表[Node]s 和 Cycle 参数返回找到的循环。

      现在cycle/4 有三个可能的选项:

      • 我们到达原始节点,在这种情况下,我们找到了Node 所在的循环,我们进行类似于第一个版本的处理:

        cycle(Curr,Curr,Visited,Cycle) :-
            !,
            reverse([Curr|Visited],Cycle).
        
      • 我们到达一个我们已经访问过的节点:CurrVisited 的一个元素,在这种情况下我们需要中断搜索:否则我们将循环无限次:

        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).
      

      \+ 表示不是

      【讨论】:

      • 谢谢威廉,我真的很感谢你的回答,它对我帮助很大。现在我完全明白了。谢谢
      猜你喜欢
      • 2011-07-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-09-06
      相关资源
      最近更新 更多