【问题标题】:OutputError: Find the longest path in a matrix with given constraintsOutputError:在给定约束的矩阵中找到最长的路径
【发布时间】:2017-04-13 00:04:22
【问题描述】:

我的矩阵是:

4 8 7 3 
2 5 9 3 
6 3 2 5 
4 4 1 6

问题(滑雪):

每个数字代表该山区的海拔

从网格中的每个区域(即方框),您可以前往northsoutheastwest strong> - 但前提是您要进入的区域的海拔低于您所在的区域。

即你只能滑雪下坡。

您可以从地图上的任何地方开始,并且您正在寻找具有可能的最长路径的起点,以您访问的盒子数量来衡量。

如果有几条相同长度的路径,您希望选择具有垂直落差最大的路径,即起始海拔和结束海拔之间的最大差异。

我的解决方案:

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。

【问题讨论】:

  • 当您的程序中没有任何内容可以以该格式打印时,您怎么能期望该输出?您当前的输出是一串没有说明目的的海拔。这个程序发生了什么?
  • 你能再读一遍这个问题吗?预期输出为:[5,8,[9,5,3,2,1]]
  • 我读到了这个问题。这并不能解释你的程序是如何设计来解决它的。不过,我想我已经弄清楚你在做什么了。

标签: python python-3.x recursion dynamic-programming depth-first-search


【解决方案1】:

人们可以通过两种不同的方式来解决问题中描述的挑战:

  1. 使用递归算法,如果满足给定要求,则在遍历矩阵元素时仅检查有效路径

  2. 分两步完成:

    2.1。通过简单调用 itertools 模块中的可用函数 permutations() 来获取所有可能路径的迭代器

    2.2。从生成的路径中挑选满足要求的路径

第二种方法的代码更容易编写和理解,但是对于 4x4 大小的矩阵已经有大量可能的路径,因此实际上不可能针对更大的矩阵大小运行它。

第一种方法的代码可以处理更大尺寸的矩阵,但缺点是在其他约束的情况下更难掌握调整它的工作原理。

这里提出的问题是两年前提出的问题here on stackoverflow100% 1:1 重复,标题为“矩阵路径中的最大元素数”。无论如何,这里再次在回答那个旧问题时给出了解决方案:

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,

我希望代码是不言自明的,但如果不是这里粗略的想法:

  1. 构建一个表示矩阵的字典,其中键是(列,行)“坐标”的元组,值是矩阵中的值。

  2. 构建矩阵中所有可能的完整路径的列表(排列)

  3. 过滤所有可能的完整路径列表,以根据需要(应用标准)仅提取有效路径。

我没有对 4x4 矩阵的结果进行非常昂贵的计算,因为在我的盒子上肯定需要几分钟以上的时间。

为了完整起见,我想提一下还有另一个问题HERE on stackoverflow 这是这个问题的一个变体(它有一些其他的有效路径规则,并要求一个能够处理不规则矩阵的算法) .

【讨论】:

  • 这正是我所需要的。但是我的目标是在 1000x1000 矩阵上尝试它,所以一旦我弄清楚如何降低时间和空间的复杂性,我就会更新我的解决方案。
【解决方案2】:

这样做的主要问题是您没有进行任何形式的回溯。您正在适当地遍历矩阵,但您没有做任何事情来维护特定路径的概念。相反,对于您访问的每个方格,您只需将所有合法移动附加到一个列表中。

相反,请考虑将当前路径保留为局部变量。对于给定方格的每个合法移动,您进行单独的递归调用以查找更多移动。每一个都会在 local 路径的末尾添加一个合法的移动。

每次通话返回时,将找到的最佳路径与您保存的路径(目前为止最好的)进行比较;保持这两者的优势,然后进行下一个合法的举动。当您考虑了四个方向中的每一个后,将最知名的路径返回到调用实例。

网上和本站有很多回溯的例子;找出一些你认为可以理解的。您可能会在硬币组合递归下查看(查找添加到一定数量的一组硬币)-它们不是相同的算法,但是上面的回溯思想显示得更清楚。

这是否会让您朝着解决方案迈进?

【讨论】:

  • 是的,现在确实有意义。
猜你喜欢
  • 1970-01-01
  • 2018-10-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多