检查矩阵中的某些元素是否具有内聚性

时间:2015-06-03 16:54:10

标签: python algorithm

我必须编写一个非常小的Python程序来检查某些坐标组是否都连接在一起(通过一条线,而不是对角线)。接下来的两张照片显示了我的意思。在左图中,所有彩色组都是有凝聚力的,右图中没有:

cohesive groups

我已经制作了这段代码,但它似乎无法正常工作,而且我对如何解决这个问题的想法很不满意?

def cohesive(container):
   co = container.pop()
   container.add(co)
   return connected(co, container)

def connected(co, container):
   done = {co}
   todo = set(container)
   while len(neighbours(co, container, done)) > 0 and len(todo) > 0:
       done = done.union(neighbours(co, container, done))
   return len(done) == len(container)

def neighbours(co, container, done):
   output = set()
   for i in range(-1, 2):
       if i != 0:
           if (co[0] + i, co[1]) in container and (co[0] + i, co[1]) not in done:
               output.add((co[0] + i, co[1]))
           if (co[0], co[1] + i) in container and (co[0], co[1] + i) not in done:
               output.add((co[0], co[1] + i))
   return output

这是一些应该返回True的参考资料:

cohesive({(1, 2), (1, 3), (2, 2), (0, 3), (0, 4)})

这应该返回False

cohesive({(1, 2), (1, 4), (2, 2), (0, 3), (0, 4)})

两种测试都有效,但当我尝试使用不同的数字进行测试时,功能会失败。

4 个答案:

答案 0 :(得分:2)

通常,要检查某些内容是否已连接,您需要使用不相交的集数据结构,更有效的变体包括加权快速联合,加权快速联合和路径压缩。

这是一个实现,http://algs4.cs.princeton.edu/15uf/WeightedQuickUnionUF.java.html,您可以根据自己的需要进行修改。此外,A. Aho的“计算机算法的设计和分析”一书中的实现允许您指定添加2个连接元素的组的名称,因此我认为这是您正在寻找的修改(它只涉及使用一个额外的数组来跟踪组号)。

作为旁注,由于不相交集通常适用于数组,因此不要忘记您可以将N×N矩阵表示为大小为N * N的数组。

编辑:刚刚意识到我一开始并不清楚你在问什么,我意识到你还提到对角线组件没有连接,在这种情况下算法是如下:

0)检查所有元素是否都引用同一组。

1)迭代表示相关矩阵中坐标的对数组。

2)对于每对,制作一组满足以下公式的对:

|entry.x - otherEntry.x| + |entry.y - otherEntry.y|=1.

'entry'指的是外部for循环引用的元素。

3)检查所有组是否重叠。这可以通过“联合”您正在查看的集合来完成,如果您获得的集合超过1集,那么这些元素就没有凝聚力。

复杂度为O(n ^ 2 + n ^ 2 * log(n))。

示例:

(0,4),(1,2),(1,4),(2,2),(2,3)

0)检查它们是否在同一组中:

所有这些都属于第5组。

1)制作套装:

set1:(0,4),(1,4)

set2:(1,2),(2,2)

set3:(0,4),(1,4)//这里我们假设集合是排序的,而不是它 应该是(1,4),(0,4)

set4:(1,2),(2,2),(2,3)

set5:(2,2),(2,3)

2)检查重叠:

set1与set3重叠,所以我们得到:

set1':( 0,4),(1,4)

set2与set4重叠并设置为5,因此我们得到:

set2':( 1,2),(2,2),(2,3)

你可以看到set1'和set2'没有重叠,因此你得到2个在同一组中的不相交集,所以答案是'false'。

请注意,这是效率低下的,但我不知道如何更有效地执行此操作,但这可以回答您的问题。

答案 1 :(得分:2)

您可以在可能的情况下获取元素并附加其邻居。

def dist(A,B):return abs(A[0]-B[0]) + abs(A[1]-B[1])

def grow(K,E):return {M for M in E for N in K if dist(M,N)<=1}

def cohesive(E):
    K={min(E)} # an element 
    L=grow(K,E)
    while len(K)<len(L) : K,L=L,grow(L,E)
    return len(L)==len(E)

grow(K,E)返回K的邻域。

In [1]: cohesive({(1, 2), (1, 3), (2, 2), (0, 3), (0, 4)})
Out[1]: True

In [2]: cohesive({(1, 2), (1, 4), (2, 2), (0, 3), (0, 4)})
Out[2]: False

答案 2 :(得分:1)

连接功能中的逻辑似乎有误。你制作了一个todo变量,但从不改变它的内容。你总是在同一个起点寻找邻居。

请尝试使用此代码:

def connected(co, container):
   done = {co}
   todo = {co}
   while len(todo) > 0:
       co = todo.pop()
       n = neighbours(co, container, done)
       done = done.union(n)
       todo = todo.union(n)
   return len(done) == len(container)

todo是我们还要检查的所有要点的集合。

done是我们发现的4个连接到起点的所有点的集合。

答案 3 :(得分:1)

我会以不同的方式解决这个问题...如果你正在寻找五个,那意味着:

  1. 该行中的每个坐标都必须与该行中的另一个坐标相邻,因为任何不足都意味着该坐标已断开。
  2. 至少有三个坐标必须与行中另外两个或多个坐标相邻,因为任何更少的坐标都将被断开。
  3. 因此,您可以获取坐标的邻居并检查是否满足两个条件。

    这是一个基本的解决方案:

    def cells_are_connected(connections):
        return all(c > 0 for c in connections)
    
    def groups_are_connected(connections):
        return len([1 for c in connections if c > 1]) > 2
    
    def cohesive(coordinates):
        connections = []
        for x, y in coordinates:
            neighbours = [(x-1, y), (x+1, y), (x, y-1), (x, y+1)]
            connections.append(len([1 for n in neighbours if n in coordinates]))
        return cells_are_connected(connections) and groups_are_connected(connections)
    
    print cohesive([(1, 2), (1, 3), (2, 2), (0, 3), (0, 4)]) # True
    print cohesive([(1, 2), (1, 4), (2, 2), (0, 3), (0, 4)]) # False
    

    无需通用案例解决方案或联合逻辑。 :)请注意,它是特定于五线的问题。