【问题标题】:Prolog - extract edges from an adjacency matrixProlog - 从邻接矩阵中提取边缘
【发布时间】:2015-01-18 21:02:11
【问题描述】:

我有一个表示图的邻接矩阵的列表列表。
我正在寻找一种从中提取图形边缘的方法:

?- getEdges([[0,1,0,0],[1,0,1,1],[0,1,0,0],[0,1,0,0]],Edges).
Edges = [[1,2],[2,4],[2,3]]

谢谢

【问题讨论】:

  • [1,2] 代表什么顶点?也许你的意思是边缘?
  • 你是对的,更正了
  • 你有尝试过吗?你到底卡在哪里了?从您的示例结果来看,这是一个无向图?

标签: list prolog graph-theory


【解决方案1】:

解决方案(假设是有向图)可能类似于以下内容:

假设您正在检查邻接矩阵并且您位于某一行。您需要一个谓词来检查该行的邻接列表并过滤掉所有0-元素,生成一个包含以下元素的列表:

(From, To)

其中From 对应于行索引,To 对应于非零列。 执行此操作的简单谓词将称为 like

?- rowEdges(Row, AdjList, Result).

所以你可以尝试这样做:

rowEdges(Row, AdjList, Result) :- edges(AdjList, 1, Row, [], Result).

edges([H|T], Column, Row, Acc, Res) :-
    NewColumn is Column + 1,
    ( H =:= 1 -> edges(T, NewColumn, Row, [(Row, Column)|Acc], Res);
      edges(T, NewColumn, Row, Acc, Res)).
edges([], _, _, Res, Res).

谓词edges/5 检查行的邻接列表的每个元素,同时跟踪元素的列索引。如果应该添加一条边,它将采用(Row, Column) 的形式,这就是我们必须提供Row 作为参数的原因。

rowEdges/3 只是提供正确的初始化,对于累加器 (Acc) 应该是一个空列表,对于列索引应该是 1。 现在您只需将rowEdges/3 应用到您必须通过类似过程找到所有边的每一行。

例子:

?- rowEdges(2, [1,0,1,1,0,1], Result).
Result = [(2, 6), (2, 4), (2, 3), (2, 1)].

如果您希望按列升序生成边,您只需修改rowEdges/3 以产生反向输出,因为edges/5 使用累加器。

rowEdges(Row, AdjList, Result) :- edges(AdjList, 1, Row, Acc, Res), reverse(Res, Result).

【讨论】:

    【解决方案2】:

    另一种方法是,首先,创建一个标识有效边的谓词。对于无向图,这里有一个简单的谓词:

    edge(M, [R,C]) :-
        nth1(R, M, Row),
        nth1(C, Row, 1),
        R =< C.               % Remove this for directed graphs
    

    这是一个示例查询:

    | ?- edge([[0,1,0,0],[1,0,1,1],[0,1,0,0],[0,1,0,0]],Edge).
    
    Edge = [1,2] ? a
    
    Edge = [2,3]
    
    Edge = [2,4]
    
    (1 ms) no
    | ?-
    

    它用每个回溯标识每个边。它使用了nth1/3 谓词,即关系nth1(N, List, Element),表示Element 位于List 中的N 位置,其中第一个元素是元素编号@987654328 @。

    对于有向图,只需去掉R =&lt; C 条件,即可得到:

    | ?- edge([[0,1,0,0],[1,0,1,1],[0,1,0,0],[0,1,0,0]],Edge).
    
    Edge = [1,2] ? a
    
    Edge = [2,1]
    
    Edge = [2,3]
    
    Edge = [2,4]
    
    Edge = [3,2]
    
    Edge = [4,2]
    
    (1 ms) no
    | ?-
    

    如果您想用另一种方式来表示一条边而不是 2 元素列表 [R,C],您只需将子句的头部从 edge(M, [R,C]) 更改为,例如,edge(M, R-C)

    | ?- edge([[0,1,0,0],[1,0,1,1],[0,1,0,0],[0,1,0,0]],Edge).
    
    Edge = 1-2 ? a
    
    Edge = 2-3
    
    Edge = 2-4
    
    (1 ms) no
    | ?-
    

    如果您想将所有边收集到一个列表中,可以使用setof/3

    all_edges(M, Edges) :-
        setof(E, edge(M, E), Edges).
    
    | ?- all_edges([[0,1,0,0],[1,0,1,1],[0,1,0,0],[0,1,0,0]],E), Edges).
    
    Edges = [1-2,2-3,2-4]
    
    yes
    | ?-
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-08-06
      • 1970-01-01
      • 2019-09-07
      • 1970-01-01
      • 1970-01-01
      • 2013-03-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多