我有一个列表列表,它代表图表的邻接矩阵 我正在寻找一种从中提取图形边缘的方法:
?- 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]]
THX
答案 0 :(得分:0)
解决方案(假设有向图)有点像以下内容:
假设您正在检查邻接矩阵,并且您处于某一行。您需要一个谓词来检查此行的邻接列表并过滤掉所有0
- 元素,从而生成包含以下格式元素的列表:
(From, To)
其中From
对应于行索引,To
对应于非零列。
执行此操作的简单谓词将被称为
?- 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).
答案 1 :(得分:0)
另一种方法是,首先创建一个标识有效边的谓词。对于无向图,这是一个简单的谓词:
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
位于N
中的位置List
,其中第一个元素是元素编号1
。
对于有向图,只需删除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,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
| ?-