我必须编写一个非常小的Python程序来检查某些坐标组是否都连接在一起(通过一条线,而不是对角线)。接下来的两张照片显示了我的意思。在左图中,所有彩色组都是有凝聚力的,右图中没有:
我已经制作了这段代码,但它似乎无法正常工作,而且我对如何解决这个问题的想法很不满意?
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)})
两种测试都有效,但当我尝试使用不同的数字进行测试时,功能会失败。
答案 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)
我会以不同的方式解决这个问题...如果你正在寻找五个,那意味着:
因此,您可以获取坐标的邻居并检查是否满足两个条件。
这是一个基本的解决方案:
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
无需通用案例解决方案或联合逻辑。 :)请注意,它是特定于五线的问题。