有一点背景知识,我根本不是计算机科学家或程序员(我在大学里学习过一些python的研究过的物理学)。我的问题是通过具有给定规则集的矩阵找到最长的路径。矩阵示例如下所示:
[0, 0, 0, 0, 0],
[0, 1, 0, 0, 0],
[1, 1, 1, 0, 0],
[0, 0, 0, 0, 0],
[1, 0, 0, 1, 0],
规则如下:
从给定的“ 1”位置开始,这些是有效位置。
每次跳转都必须移至同一行或同一列上的另一个有效位置(可以跳过“ 0”)。
连续跳跃不能在同一方向上(水平/垂直),除非从对角线位置跳跃。
示例矩阵上的有效路径如下:
(5,4),(5,1),(3,1),(3,3),(3,2),(2,2)
由于规则3而导致的无效路径如下:
(3,1),(3,2),(3,3)
可能会出现以下 :
(3,1),(3,3),(3,2)
尽管我对python有一定的经验,但我从未尝试过递归(我很确定这是解决此问题的方法),而且我似乎无法在我的水平上找到任何在线帮助。
答案 0 :(得分:1)
有几种解决方案。我建议先将网格转换为更面向对象的结构,即无向图,其中的节点在输入中为1。
然后,我将在该图中区分三种边缘:
在重复进行时,您将始终考虑特殊的边缘,除此之外,还要考虑其他两组边缘之一中的边缘(基于以前的方向)。
这是一个实现:
class Node:
def __init__(self, y, x, size):
self.x = x
self.y = y
self.coord = (y, x)
self.diagonal = x == y or size - 1 - y
# Separate lists of neighbors: vertical, horizontal.
# Third list is for when this node or neighbor is on diagonal
self.neighbors = [[], [], []]
def addNeighbor(self, node, direction):
self.neighbors[direction].append(node)
class Maze:
def __init__(self, grid):
def addedge(a, b):
direction = 2 if a.diagonal or b.diagonal else int(a.x == b.x)
a.addNeighbor(b, direction)
b.addNeighbor(a, direction)
# alternative grid having Node references:
self.nodes = [[None] * len(grid) for _ in grid]
colNodes = [[] for _ in grid]
for y, row in enumerate(grid):
rowNodes = []
for x, cell in enumerate(row):
if cell: # only create nodes for when there is a 1 in the grid
node = Node(y, x, len(grid))
for neighbor in rowNodes + colNodes[x]:
addedge(node, neighbor)
rowNodes.append(node)
colNodes[x].append(node)
self.nodes[y][x] = node
def findpath(self, y, x):
def recur(node, neighbors):
visited.add(node)
longest = [node.coord]
# always visit "special" neighbors
# (i.e. those on diagonal or all vert/horiz when node is on diagonal)
for neighbor in node.neighbors[2] + neighbors:
if not neighbor in visited:
# toggle direction when going further
path = recur(neighbor, node.neighbors[1-int(node.x == neighbor.x)])
if len(path) >= len(longest):
longest = [node.coord] + path
visited.remove(node)
return longest
node = self.nodes[y][x]
if not node:
raise "Cannot start from that position"
visited = set()
# look in both directions of starting node
return recur(node, node.neighbors[0] + node.neighbors[1])
grid = [
[0, 0, 0, 0, 0],
[0, 1, 0, 0, 0],
[1, 1, 1, 0, 0],
[0, 0, 0, 0, 0],
[1, 0, 0, 1, 0]
]
maze = Maze(grid)
path = maze.findpath(2, 0)
print(path) # output: [(2, 0), (2, 2), (2, 1), (1, 1)]
path = maze.findpath(4, 3)
print(path) # output: [(4, 3), (4, 0), (2, 0), (2, 2), (2, 1), (1, 1)]
请注意,此解决方案中的坐标是从零开始的,因此第一行的编号为0,...等。
看到它在repl.it上运行
答案 1 :(得分:0)
您可以将递归与生成器一起使用:
d = [[0, 0, 0, 0, 0], [0, 1, 0, 0, 0], [1, 1, 1, 0, 0], [0, 0, 0, 0, 0], [1, 0, 0, 1, 0]]
_d = {1:lambda a, b:'f' if b[-1] > a[-1] else 'b', 0:lambda a, b:'u' if b[0] > a[0] else 'd'}
def paths(start, _dir, c = []):
yield c
_options = [(a, b) for a in range(len(d)) for b in range(len(d[0])) if (a, b) not in c and d[a][b]]
if _options:
for a, b in _options:
if a == start[0] or b == start[-1]:
r = _d[a == start[0]](start, (a, b))
if _dir is None or r != _dir:
yield from paths((a, b), r, c+[(a, b)])
print(max(list(paths((4, 3), None, [(4, 3)])), key=len))
输出:
[(4, 3), (4, 0), (2, 0), (2, 2), (2, 1), (1, 1)]