我的矩阵是:
4 8 7 3
2 5 9 3
6 3 2 5
4 4 1 6
问题(滑雪):
每个数字代表该山区的海拔。
从网格中的每个区域(即框),您可以去北,南,东,西 - 但前提是您要进入的区域的高度 小于您所在的区域。
即。你只能滑雪下坡。
您可以从地图上的任意位置开始,并且您正在寻找一个起点,其中可能的最长路径以您访问的方框数量来衡量。
如果有多条相同长度的路径,您想要使用最陡垂直下降的路径,即起始高程与结束高程之间的最大差异。
我的解决方案:
def findSkiPath():
mySolution = [0] * 3
mySolution[0] = 0 # Distance
mySolution[1] = 0 # Drop
cellIndexRow = 0
cellIndexCol = 0
myPath = []
myMatrix = [[4, 5, 8, 7],[1, 1, 5, 9], [0, 7, 5, 5], [7, 4, 2, 9]]
countRows = len(myMatrix)
countCols = len(myMatrix[0])
for i in range(0, countRows - 1):
for j in range(0, countCols - 1):
myValue = myMatrix[i][j]
myPath.append(myValue)
#check east
cellIndexRow = i
cellIndexCol = j + 1
checkAdjacentCells(cellIndexRow, cellIndexCol, myValue, myMatrix , mySolution , myPath )
#check west
cellIndexRow = i
cellIndexCol = j - 1
checkAdjacentCells(cellIndexRow, cellIndexCol, myValue, myMatrix , mySolution , myPath )
#check north
cellIndexRow = i - 1
cellIndexCol = j
checkAdjacentCells(cellIndexRow, cellIndexCol, myValue, myMatrix , mySolution , myPath )
#check south
cellIndexRow = i + 1
cellIndexCol = j
checkAdjacentCells(cellIndexRow, cellIndexCol, myValue, myMatrix , mySolution , myPath )
print (mySolution)
def checkAdjacentCells(cellIndexRow, cellIndexCol, myValue, myMatrix , mySolution , myPath ):
#The base case - If we go beyond the limits of the matrix
if (cellIndexRow < 0 or cellIndexRow > (len(myMatrix) - 1) or cellIndexCol < 0 or cellIndexCol > (len(myMatrix[0]) - 1)):
evaluateSolution(mySolution , myPath )
return
#check if the next cell has a lower value than the current cell
tmpValue = myMatrix[cellIndexRow][cellIndexCol]
if tmpValue < myValue:
newPath = myPath
newPath.append(tmpValue)
r = cellIndexRow
c = cellIndexCol
#check east
cellIndexRow = r
cellIndexCol = c + 1
checkAdjacentCells(cellIndexRow, cellIndexCol, tmpValue, myMatrix , mySolution , newPath )
#check west
cellIndexRow = r
cellIndexCol = c - 1
checkAdjacentCells(cellIndexRow, cellIndexCol, tmpValue, myMatrix , mySolution , newPath )
#check north
cellIndexRow = r - 1
cellIndexCol = c
checkAdjacentCells(cellIndexRow, cellIndexCol, tmpValue, myMatrix , mySolution , newPath )
#check south
cellIndexRow = r + 1
cellIndexCol = c
checkAdjacentCells(cellIndexRow, cellIndexCol, tmpValue, myMatrix , mySolution , newPath )
evaluateSolution(mySolution , myPath )
def evaluateSolution(mySolution , myPath ):
myDistance = 1
mySolutionDistance = int(mySolution[0])
mySolutionDrop = int(mySolution[1])
if myDistance < mySolutionDistance:
return
myDrop = myPath[0] - myPath[-1]
if myDistance > mySolutionDistance or myDrop > mySolutionDrop:
mySolution[0] = myDistance
mySolution[1] = mySolutionDrop
mySolution[2] = myPath
if __name__ == "__main__":
findSkiPath()
的问题:
当前输出(距离,跌落,路径):
[1,0,[4,2,8,7,3,4,2,5,2,3,2,1,7,3,2,5,2,3,2,1,9] , 3,5,2,3,2,1,7,3,2,1,6,3,2,1,2,4,3,2,1,2,1]]
预期产出:
[5,8,[9,5,3,2,1]]
在这个特定的地图上,最长的路径是长度= 5,掉落= 8(9-1 = 8),路径:9-5-3-2-1。
答案 0 :(得分:2)
人们可以通过两种不同的方式接近所述挑战中的问题:
使用递归算法,如果满足给定的要求,则在迭代遍历矩阵元素时仅检查已经检查的有效路径
分两步完成:
2.1。通过简单调用itertools
模块可用函数permutations()
2.2。从生成的路径中挑选出符合要求的路径
第二种方法的代码更易于编写和理解,但是对于4x4大小的矩阵而言已经存在大量可能的路径,因此实际上不可能为更大的矩阵大小运行它。
第一种方法的代码可以处理更大尺寸的矩阵,但缺点是在其他约束的情况下更难理解它如何调整它。
这里提出的问题是两年前提出的一个问题的 100%1:1重复 here on stackoverflow,标题为“矩阵路径中元素的最大数量”。无论如何,这里的解决方案再次回答了那个老问题:
theMatrix = [
[ 4, 8, 7, 3],
[ 2, 5, 9, 3],
[ 6, 3, 2, 5],
[ 4, 4, 1, 6]
]
def longest_path(matrix):
def inner_longest_path(x, y):
best, best_path = 0, []
# for all possible neighbor cells...
for dx, dy in ((+1, 0), (-1, 0), (0, +1), (0, -1)):
# if cell is valid and strictly smaller...
if (0 <= x + dx < len(matrix) and 0 <= y + dy < len(matrix[x])
and matrix[x+dx][y+dy] < matrix[x][y]):
n, path = inner_longest_path(x+dx, y+dy) ### RECURSION
# check if the path starting at that cell is better
if n > best:
best, best_path = n, path
return best + 1, [matrix[x][y]] + best_path
return max(inner_longest_path(x, y) for x, row in enumerate(matrix)
for y, _ in enumerate(row))
print( longest_path(theMatrix) )
上面的代码打印:
(5, [9, 5, 3, 2, 1])
现在让我们来看看这里提供的非递归方法的代码:我自己:
# myMatrix = [[4, 5, 8, 7],[1, 1, 5, 9], [0, 7, 5, 5], [7, 4, 2, 9]]
# 4 5 8 7
# 1 1 5 9
# 0 7 5 5
# 7 4 2 9
myMatrix = [[4, 5, 8],[1, 1, 5], [0, 7, 5]]
# 4 5 8
# 1 1 5
# 0 7 5
# myMatrix = [[4, 5],[1, 1]]
# 4 5
# 1 1
def getAllValidSkiingPathsFrom(myMatrix):
# def getDictRepresentationOf(myMatrix):
dctOfMatrix = {}
for row in range(len(myMatrix)):
for column in range(len(myMatrix[0])):
currPoint = (column, row)
dctOfMatrix[currPoint] = myMatrix[row][column]
lstIndicesOfAllMatrixPoints = list(dctOfMatrix.keys())
setAllPossiblePaths = set()
from itertools import permutations
for pathCandidate in permutations(lstIndicesOfAllMatrixPoints):
lstPossiblePath = []
prevIndexTuple = pathCandidate[0]
lstPossiblePath.append(prevIndexTuple)
for currIndexTuple in pathCandidate[1:]:
if abs(currIndexTuple[0]-prevIndexTuple[0]) + abs(currIndexTuple[1]-prevIndexTuple[1]) > 1:
break # current path indices not allowed in path (no diagonals or jumps)
else:
if dctOfMatrix[currIndexTuple] >= dctOfMatrix[prevIndexTuple]:
break # only "down" is allowed for "skiing"
else:
lstPossiblePath.append(currIndexTuple)
prevIndexTuple = currIndexTuple
if len(lstPossiblePath) > 1 and tuple(lstPossiblePath) not in setAllPossiblePaths:
setAllPossiblePaths.add(tuple(lstPossiblePath))
return setAllPossiblePaths, dctOfMatrix
#:def getAllValidSkiingPathsFrom
setAllPossiblePaths, dctOfMatrix = getAllValidSkiingPathsFrom(myMatrix)
for path in setAllPossiblePaths:
for point in path:
print(dctOfMatrix[point], end=',')
这里是myMatrix的2x2和3x3版本的结果:
# 4 5
# 1 1
4,1,
5,1,
5,4,
5,4,1,
# 4 5 8
# 1 1 5
# 0 7 5
5,1,
8,5,1,
7,1,
4,1,
5,1,
5,4,
8,5,1,
1,0,
5,4,1,0,
8,5,4,1,
8,5,4,1,0,
8,5,4,
8,5,
7,0,
7,5,
8,5,
4,1,0,
5,4,1,
我希望代码是不言自明的,但如果不是这里粗略的想法:
构建一个表示矩阵的字典,其中键是(列,行)“坐标”的元组,而值是矩阵中的值。
建立矩阵内所有可能的完整路径列表(排列)
过滤所有可能的完整路径列表,根据需要仅提取有效路径(应用标准)。
我没有运行计算非常昂贵的4x4矩阵结果计算,因为它在我的盒子上肯定需要几分钟。
为了完整起见,我想提一下,还有另一个问题HERE on stackoverflow,它是这个问题的一个变体(它有一些其他有效路径的规则,并要求算法能够处理不规则的问题矩阵)。
答案 1 :(得分:1)
这个问题的主要问题是你不做任何回溯。您正在适当地遍历矩阵,但是您没有做任何事情来维护特定路径的概念。相反,对于您访问的每个方格,您只需将所有合法移动附加到单个列表中。
相反,请考虑将当前路径保持为局部变量。对于来自给定方格的每个合法移动,您进行单独的递归调用以查找更多移动。其中每一项都会在本地路径的末尾添加合法移动。
当您从每次通话中返回时,将找到的最佳路径与您保存的路径进行比较(目前为止最好);保持这两者的优势,并进入下一个法律行动。当您考虑了四个方向中的每个方向时,请将最有名的路径返回到调用实例。
在线和本网站上有很多回溯的例子;找出一些你觉得可以理解的东西。您可以查看硬币组合递归(找到一组添加到一定数量的硬币) - 它们不是相同的算法,但上面的回溯想法会更清楚地显示出来。
这会让你走向解决方案吗?