假设我有以下矩阵(在Julia语言中定义):
mat = [1 1 0 0 0 ; 1 1 0 0 0 ; 0 0 0 0 1 ; 0 0 0 1 1]
将一组具有值'1'的邻居元素视为“组件”,如何识别该矩阵有2个组件以及哪个顶点组成每个组件?
对于上面的矩阵 mat ,我想找到以下结果:
组件1由矩阵的以下元素(行,列)组成:
(1,1)
(1,2)
(2,1)
(2,2)
组件2由以下元素组成:
(3,5)
(4,4)
(4,5)
我可以使用像this这样的图形算法来识别方形矩阵中的组件。然而,这样的算法不能用于非方形矩阵,就像我在这里提出的那样。
任何想法都会受到高度赞赏。
如果你的建议涉及使用Python库+ PyCall,我是开放的。虽然我更喜欢使用纯Julia解决方案。
此致
答案 0 :(得分:4)
使用Image.jl
的{{1}}确实是解决核心问题的最简单方法。但是,您在label_components
上的循环可能效率不高:1:maximum(labels)
,其中O(N*n)
是N
中元素的数量,labels
是最大值,因为您访问n
labels
次的每个元素。
只需两次访问n
的每个元素,你会好得多:一次确定最大值,一次将每个非零元素分配给其正确的组:
labels
测试矩阵的输出:
using Images
function collect_groups(labels)
groups = [Int[] for i = 1:maximum(labels)]
for (i,l) in enumerate(labels)
if l != 0
push!(groups[l], i)
end
end
groups
end
mat = [1 1 0 0 0 ; 1 1 0 0 0 ; 0 0 0 0 1 ; 0 0 0 1 1]
labels = label_components(mat)
groups = collect_groups(labels)
调用像2-element Array{Array{Int64,1},1}:
[1,2,5,6]
[16,19,20]
这样的库函数有时会很有用,但它也是一种习惯于慢速语言的习惯,值得留下。在朱莉娅,你可以编写自己的循环,它们会很快;更好的是,通常生成的算法更容易理解。 find
并没有完全消失。
答案 1 :(得分:1)
答案很简单(虽然我不能提供python代码):
在伪代码中(使用BFS):
//generate a list with the position of all 1s in the matrix
list pos
for int x in [0 , matrix_width[
for int y in [0 , matrix_height[
if matrix[x][y] == 1
add(pos , {x , y})
while NOT isempty(pos)
//traverse the graph using BFS
list visited
list next
add(next , remove(pos , 0))
while NOT isempty(next)
pair p = remove(next , 0)
add(visited , p)
remove(pos , p)
//p is part of the specific graph that is processed in this BFS
//each repetition of the outer while-loop process a different graph that is part
//of the matrix
addall(next , distinct(visited , neighbour1s(p)))
答案 2 :(得分:1)
刚从julia-users邮件列表中得到答案,使用Images.jl解决了这个问题,这是一个在Julia中处理图像的库。
他们开发了一个名为" label_components"识别矩阵中的连通分量。
然后我使用名为" findMat"的定制函数。获得每个组件的这种组件矩阵的索引。
答案,朱莉娅语言:
using Images
function findMat(mat,value)
return(collect(zip(ind2sub(size(mat),find( x -> x == value, mat))...)));
end
mat = [1 1 0 0 0 ; 1 1 0 0 0 ; 0 0 0 0 1 ; 0 0 0 1 1]
labels = label_components(mat);
for c in 1:maximum(labels)
comp = findMat(labels,c);
println("Component $c is composed by the following elements (row,col)");
println("$comp\n");
end