python 是否有一个算法来概括这种模式的创建?

r7knjye2  于 2023-01-01  发布在  Python
关注(0)|答案(3)|浏览(140)

我需要以如下所示的模式连接这些节点:

所有的节点(圆圈)都存储在一个列表中,然后我有一个2d列表,其中有一对数字,这些数字指的是节点的索引,并显示它们之间的连接。为了创建图中所示的排列,我手动将连接列表存储在一个变量中。
我希望有一种方法可以接收这个点列表,然后返回这个所有点连接的列表,这对任何数量的点都有效。
我试图通过使用itertools组合来实现:

connections=list(combinations(points, 2))
# draw combinations with lines between each point pair

结果:

它给了我错误的结果,正如你所看到的,有太多的连接,它不遵循上面的例子中显示的模式,我手动给出了连接。

wswtfjt7

wswtfjt71#

需要显式指定边。
对于坐标(i, j)处的每个点,存在到其东(i, j+1)的点的水平边、到其南(i+1, j)的点的垂直边、到其东南(i+1, j+1)的点的对角边以及到其东北(i-1,j+1)的点的对角边。

def grid(h, w):
    vertices = [(i, j) for i in range(h) for j in range(w)]
    edges = [((i,j), (i+di, j+dj))
             for i in range(h-1) for j in range(w-1)
             for (di, dj) in ((0, 1), (1, 0), (1, 1))]
    edges.extend(((i,j), (i-1,j+1))
                 for i in range(1,h) for j in range(w-1))
    edges.extend(((i, w-1), (i+1, w-1)) for i in range(h-1))
    edges.extend(((h-1, j), (h-1, j+1)) for j in range(w-1))
    return vertices, edges

def grid_with_simple_numbers_instead_of_pairs(h, w):
    vertices, edges = grid(h, w)
    vertices = [i * w + j for (i, j) in vertices]
    edges = [((i*w+j), (k*w+l)) for ((i,j), (k,l)) in edges]
    return vertices, edges

## OR EQUIVALENTLY
def grid_with_simple_numbers(h, w):
    vertices = list(range(h * w))
    edges = [(i*w+j, i*w+j+k)
             for i in range(h-1) for j in range(w-1)
             for k in (1, w, w+1)]
    edges.extend((i*w+j, (i-1)*w+j+1)
             for i in range(1,h) for j in range(w-1))
    edges.extend((ij, ij+w) for ij in range(w-1, h*w-1, w))
    edges.extend((ij, ij+1) for ij in range((h-1)*w, h*w-1))
    return vertices, edges

print(grid(2, 2))
# [(0, 0), (0, 1), (1, 0), (1, 1)],
# [((0, 0), (0, 1)), ((0, 0), (1, 0)), ((0, 0), (1, 1)), ((1, 0), (0, 1)), ((0, 1), (1, 1)), ((1, 0), (1, 1))]

print(grid_with_simple_numbers_instead_of_pairs(2, 2))
# [0, 1, 2, 3],
# [(0, 1), (0, 2), (0, 3), (2, 1), (1, 3), (2, 3)]

print(grid_with_simple_numbers(2, 2))
# [0, 1, 2, 3],
# [(0, 1), (0, 2), (0, 3), (2, 1), (1, 3), (2, 3)]

测试:

import networkx as nx
import matplotlib.pyplot as plt

vertices, edges = grid_with_simple_numbers_instead_of_pairs(4, 3)
G = nx.Graph()
G.add_nodes_from(vertices)
G.add_edges_from(edges)
nx.draw(G, with_labels=True)
plt.show()

db2dz4w8

db2dz4w82#

具有显式边的答案已经存在。
另一方面,您可能需要显式地指定边--以及节点。
考虑下面的方法,一个节点就是一对(row, col)和一个网格坐标,一个连接并不存储在任何地方:相反,对于每个节点,其邻居是即时生成的。
下面是第二张图片的示例:

deltas = [(-1, -1), (-1,  0), (-1, +1), ( 0, +1),
          (+1, +1), (+1,  0), (+1, -1), ( 0, -1)]

rows = 3
cols = 2

def neighbors (row, col):
    res = []
    for dr, dc in deltas:
        nr, nc = row + dr, col + dc
        if 0 <= nr <= rows and 0 <= nc <= cols:
            res.append ((nr, nc))
    return res

for row in range (0, rows + 1):
    for col in range (0, cols + 1):
        print ((row, col), '->', neighbors (row, col))

下面是它打印的邻居:

(0, 0) -> [(0, 1), (1, 1), (1, 0)]
(0, 1) -> [(0, 2), (1, 2), (1, 1), (1, 0), (0, 0)]
(0, 2) -> [(1, 2), (1, 1), (0, 1)]
(1, 0) -> [(0, 0), (0, 1), (1, 1), (2, 1), (2, 0)]
(1, 1) -> [(0, 0), (0, 1), (0, 2), (1, 2), (2, 2), (2, 1), (2, 0), (1, 0)]
(1, 2) -> [(0, 1), (0, 2), (2, 2), (2, 1), (1, 1)]
(2, 0) -> [(1, 0), (1, 1), (2, 1), (3, 1), (3, 0)]
(2, 1) -> [(1, 0), (1, 1), (1, 2), (2, 2), (3, 2), (3, 1), (3, 0), (2, 0)]
(2, 2) -> [(1, 1), (1, 2), (3, 2), (3, 1), (2, 1)]
(3, 0) -> [(2, 0), (2, 1), (3, 1)]
(3, 1) -> [(2, 0), (2, 1), (2, 2), (3, 2), (3, 0)]
(3, 2) -> [(2, 1), (2, 2), (3, 1)]

这里的要点是,当我们每次需要连接时都可以动态生成它们时,通常不需要“存储”连接。大多数图算法(从BFS、DFS和最短路径开始)依赖于“对于此节点的每个邻居,执行此操作”形式的基本操作。在代码中,此短语可以替换为:

... # "this node" is (row, col)
    for dr, dc in deltas:
        nr, nc = row + dr, col + dc
        if 0 <= nr <= rows and 0 <= nc <= cols:
            ... # "do that" with node (nr, nc)
jhkqcmku

jhkqcmku3#

正如@luk2302所说,你可以迭代所有的点,并将(x,y)连接到(x+1,y)、(x,y+1)、(x+1,y+1)和(x+1,y-1)。此外,如果你想存储点之间的连接列表,我建议使用字典形式的邻接列表。

WIDTH = 2
LENGTH = 3
points = [(0, 0), (0, 1), (1, 0), (1, 1), (2, 0), (2, 1)]
connections = {}

for p in points:
    connections[p] = []

for p in points:
    if p[0] < LENGTH-1:
        connections[p].append((p[0]+1, p[1]))
        connections[(p[0]+1, p[1])].append(p)
    if p[1] < WIDTH-1:
        connections[p].append((p[0], p[1]+1))
        connections[(p[0], p[1]+1)].append(p)
    if p[0] > 0 and p[1] < WIDTH-1:
        connections[p].append((p[0]-1, p[1]+1))
        connections[(p[0]-1, p[1]+1)].append(p)
    if p[0] < LENGTH-1 and p[1] < WIDTH-1:
        connections[p].append((p[0]+1, p[1]+1))
        connections[(p[0]+1, p[1]+1)].append(p)

最后得到的是一个名为connections的字典,其中connections[(x,y)]将返回该点连接到的所有其他元组的列表。
例如,connections[(0,0)]将返回[(1,0), (0,1), (1,1)]
如果你只想画网格而不做任何操作,你也可以删除每个“if”语句的第二行。

相关问题