识别矩阵中最大的连通分量
Identifying largest connected component in a matrix
我有一个包含 1 和 0 的 python numpy 矩阵,我需要确定矩阵中 1 中最大的 "collection":
http://imgur.com/4JPZufS
矩阵最多可以有 960.000 个元素,所以我想避免暴力解决方案。
解决这个问题最明智的方法是什么?
您可以使用名为 disjoint-set (here 的数据结构是 python 实现)。这种数据结构就是为这种任务设计的。
如果当前元素为 1,则遍历行,检查是否有任何已遍历的邻居为 1。如果是,则将此元素添加到其集合中。如果有超过 1 个 union 那些集合。如果没有邻居是 1 创建一个新的集合。最后输出最大的一组。
这将按如下方式工作:
def MakeSet(x):
x.parent = x
x.rank = 0
x.size = 1
def Union(x, y):
xRoot = Find(x)
yRoot = Find(y)
if xRoot.rank > yRoot.rank:
yRoot.parent = xRoot
elif xRoot.rank < yRoot.rank:
xRoot.parent = yRoot
elif xRoot != yRoot: # Unless x and y are already in same set, merge them
yRoot.parent = xRoot
xRoot.rank = xRoot.rank + 1
x.size += y.size
y.size = x.size
def Find(x):
if x.parent == x:
return x
else:
x.parent = Find(x.parent)
return x.parent
""""""""""""""""""""""""""""""""""""""""""
class Node:
def __init__ (self, label):
self.label = label
def __str__(self):
return self.label
rows = [[1, 0, 0], [1, 1, 0], [1, 0, 0]]
setDict = {}
for i, row in enumerate(rows):
for j, val in enumerate(row):
if row[j] == 0:
continue
node = Node((i, j))
MakeSet(node)
if i > 0:
if rows[i-1][j] == 1:
disjointSet = setDict[(i-1, j)]
Union(disjointSet, node)
if j > 0:
if row[j-1] == 1:
disjointSet = setDict[(i, j-1)]
Union(disjointSet, node)
setDict[(i, j)] = node
print max([l.size for l in setDict.values()])
>> 4
这是一个完整的工作示例,其中包含取自上述 link 的不相交集代码。
我认为计数会在 结束。例如。如果行更改为 rows = [[1, 0, 0], [1, 1, 1], [1, 0, 0]]
仍然得到 4,尽管它应该是 5。将 Union 更改为
def Union(x, y):
xRoot = Find(x)
yRoot = Find(y)
if xRoot.rank > yRoot.rank:
yRoot.parent = xRoot
xRoot.size += yRoot.size
elif xRoot.rank < yRoot.rank:
xRoot.parent = yRoot
yRoot.size += xRoot.size
elif xRoot != yRoot: # Unless x and y are already in same set, merge them
yRoot.parent = xRoot
xRoot.rank = xRoot.rank + 1
xRoot.size += yRoot.size
似乎修复了。
我有一个包含 1 和 0 的 python numpy 矩阵,我需要确定矩阵中 1 中最大的 "collection": http://imgur.com/4JPZufS
矩阵最多可以有 960.000 个元素,所以我想避免暴力解决方案。
解决这个问题最明智的方法是什么?
您可以使用名为 disjoint-set (here 的数据结构是 python 实现)。这种数据结构就是为这种任务设计的。
如果当前元素为 1,则遍历行,检查是否有任何已遍历的邻居为 1。如果是,则将此元素添加到其集合中。如果有超过 1 个 union 那些集合。如果没有邻居是 1 创建一个新的集合。最后输出最大的一组。
这将按如下方式工作:
def MakeSet(x):
x.parent = x
x.rank = 0
x.size = 1
def Union(x, y):
xRoot = Find(x)
yRoot = Find(y)
if xRoot.rank > yRoot.rank:
yRoot.parent = xRoot
elif xRoot.rank < yRoot.rank:
xRoot.parent = yRoot
elif xRoot != yRoot: # Unless x and y are already in same set, merge them
yRoot.parent = xRoot
xRoot.rank = xRoot.rank + 1
x.size += y.size
y.size = x.size
def Find(x):
if x.parent == x:
return x
else:
x.parent = Find(x.parent)
return x.parent
""""""""""""""""""""""""""""""""""""""""""
class Node:
def __init__ (self, label):
self.label = label
def __str__(self):
return self.label
rows = [[1, 0, 0], [1, 1, 0], [1, 0, 0]]
setDict = {}
for i, row in enumerate(rows):
for j, val in enumerate(row):
if row[j] == 0:
continue
node = Node((i, j))
MakeSet(node)
if i > 0:
if rows[i-1][j] == 1:
disjointSet = setDict[(i-1, j)]
Union(disjointSet, node)
if j > 0:
if row[j-1] == 1:
disjointSet = setDict[(i, j-1)]
Union(disjointSet, node)
setDict[(i, j)] = node
print max([l.size for l in setDict.values()])
>> 4
这是一个完整的工作示例,其中包含取自上述 link 的不相交集代码。
我认为计数会在 rows = [[1, 0, 0], [1, 1, 1], [1, 0, 0]]
仍然得到 4,尽管它应该是 5。将 Union 更改为
def Union(x, y):
xRoot = Find(x)
yRoot = Find(y)
if xRoot.rank > yRoot.rank:
yRoot.parent = xRoot
xRoot.size += yRoot.size
elif xRoot.rank < yRoot.rank:
xRoot.parent = yRoot
yRoot.size += xRoot.size
elif xRoot != yRoot: # Unless x and y are already in same set, merge them
yRoot.parent = xRoot
xRoot.rank = xRoot.rank + 1
xRoot.size += yRoot.size
似乎修复了。