在正方形格子网格上计算直线路径的Pythonic方法?

时间:2014-06-06 04:36:51

标签: python grid-layout path-finding mathematical-lattices

我不确定如何在这里描述我的问题,所以我想我会先尝试解释一下情况。我有一个数据集从4边多边形的正方格子网格中拉出来。晶格尺寸不能保证特别是任何东西。我可以访问描述网格上任何给定点的邻居的数据(即,"点236具有到点417,872,123和331&#34的边缘;)以及它的相关信息。

我拥有的是:

graph = [set([5, 9]), set([4, 11]), set([5, 6, 12]), set([6, 10, 2]), \
         set([1, 3, 8]), set([3, 7, 4]), set([6, 12, 10, 16]), \
         set([5, 9, 18, 12]), set([1, 8, 13]), set([4, 11, 7, 15]), \
         set([2, 10, 17]), set([3, 7, 8, 14]), set([9, 18]), \
         set([18, 12, 16]), set([16, 10, 17]), set([14, 7, 15]), \
         set([15, 11]), set([13, 8, 14])]

graph[n]允许我通过索引n访问任何给定点的邻居...其中的整个数据集可以通过下面显示的2D图形显示(我没有'然后通过上面列出的数据访问其他):

*--------*--------*-------*-------*-------*
| 1      | 5      | 3     | 6     | 4     | 2
|        |        |       |       |       |
|        |        |       |       |       |
*--------*--------*-------*-------*-------*
| 9      | 8      | 12    | 7     | 10    | 11
|        |        |       |       |       |
|        |        |       |       |       |
*--------*--------*-------*-------*-------*
  13       18       14      16      15      17

我试图把它变成一组看起来像这样的数据:

u = [[1, 5, 3, 6, 4, 2], [9, 8, 12, 7, 10, 11], [13, 18, 14, 16, 15, 17]]
v = [[1, 9, 13], [5, 8, 18], [3, 12, 14], [6, 7, 16], [4, 10, 15], [2, 11, 17]]

输出数据描述了网格的平行线(从具有最低索引号的角落开始)。保证每个点具有唯一索引,并且保证网格具有连续的索引集(在这种情况下,从1到18),但不保证订单有任何方式。预先不知道网格的尺寸。每个点只有2(角点),3(边缘点)或4(点在中心某处)的价值。

现在,我已经为此写了一个蛮力的方法,但效率相当低。它包括找出前两个水平和垂直边缘(在这种情况下,[1,5,3,6,4,2]和[1,9,13]),然后"移动"每个边缘通过获得每个点的连接邻居并从中减去已经访问过的集合(所以1 - > 5,9 - > 8,13 - > 18)并重复该过程直到你到达另一侧网格。

我想知道的是,是否有更多" pythonic"处理这个问题的方法。我自己的代码被分成几个不同的阶段,但我认为必须在某种程度上做到这一点,而不是反复遍历所有这些(它现在占用了我大约60ms每次运行以计算所有这些,如果可能的话,我试图将其降低到20ms。

2 个答案:

答案 0 :(得分:0)

我认为你可以逐步构建你的网格,一次一个节点没有太多麻烦。以下是我的表现:

  1. 从任何角落节点开始,只有两个邻居才能检测到它。
  2. 通过挑选任何一个起始节点的邻居然后重复移动到具有其自己的三个邻居(而不是四个)的邻居来重新找到一条边(它并不重要),避免回到上一个节点。结束的情况是你到达另一个角落。
  3. 在您刚找到的行上循环,获取每个节点的剩余邻居。只剩下一个邻居节点(网格中尚未存在),因此这里没有复杂性。
  4. 重复步骤3,直至到达远处。
  5. 通过转置列表(例如,使用zip(*rows)
  6. 制作第二个(列中的列表)列表

    如果您的邻居数据是从每个节点到其邻居列表的字典映射形式,则此代码应该有效:

    def make_grid(neighbor_dict):
        # step 1, find the first corner
        for node, neighbors in neighbor_dict:
            if len(neighbors) == 2:
                break  # node and neighbors will hold our start corner and its neighbors
    
        # step 2, build the first edge
        row = [node, neighbor[0]]  # start with the corner, and an arbitrary neighbor
        while len(neighbors_dict[row[-1]]) == 3:
            for neighbor in neighbor_dict[row[-1]]:
                if neighbor != row[-2] and len(neighbor_dict[neighbor]) <= 3:
                    row.append(neighbor)
                    break
    
        # setup for steps 3 and 4
        seen = set(row)  # a set of all nodes we've added to the grid so far
        rows = []
        done = False
    
        while not done:  # this loop is step 4, building all rows
            rows.append(row)
            new_row = []
            for node in row:  # this is step 3, building a new row from the previous row
                for neighbor in neighbor_dict[node]:
                    if neighbor not in seen:
                        new_row.append(neighbor)
                        seen.add(neighbor)
                        break
                else:  # no break hit in for loop, only happens if `row` is the far edge
                    done = True
                    break
            row = new_row
    
        # step 5, transpose to get columns from rows
        columns = list(zip(*rows))
    
        return rows, columns
    

答案 1 :(得分:0)

您可能需要查看此代码:

def lattice_paths_of_n(n):
    list2 = []
    my_list = []
    for i in range(1, n+2):
        list2.append(i)
    for i in range(1, n+2):
        my_list.append(list2)
    for i in range(0,n+1):
        for f in range(0,n+1):
            if f == 0 or i == 0:
                my_list[i][f] = 1
            else:
                my_list[i][f] = my_list[i-1][f]+my_list[i][f-1]
    return my_list[n][n]
import math
start_time = time.time()
print(lattice_paths_of_n(20))
print(time.time()-start_time)

虽然效率很低,但我希望你觉得它很有用。