优化最低成本路径不起作用

时间:2017-02-26 15:58:10

标签: python

我试图编写一种能够以最低成本找到n * n矩阵中的路径的算法(每个坐标都有预定义的成本)。路径成本定义为所有坐标成本的总和。第一行输入包含矩阵的大小,后面的n行是表行。最后两行代码是1.开始坐标2.结束坐标。输出是最小路径成本。

示例输入:

5
0 1 2 1 1
0 0 1 5 1
1 0 0 1 1
1 1 0 7 0
1 8 0 0 0
0 0
4 4

输出应为0

这是带有memoization的代码(它没有memoization,但速度很慢)

import copy
import sys

sys.setrecursionlimit(9000)

INF = 100000

n = int(input())

memo = {}

def input_matrix(n) :
    p = []
    for i in range(n) :
        p.append(list(map(int, input().split())))
    return p

def min_cost(matrix, x, y, end_x, end_y) :
    if x == end_x and y == end_y :
        return 0
    if (x, y) in memo :
        return memo[(x, y)]
    if x == len(matrix) or y == len(matrix) or x == -1 or y == -1 or matrix[y][x] == -1:
        return INF

    z = copy.deepcopy(matrix)
    z[y][x] = -1

    memo[(x, y)] = min(
        min_cost(z, x+1, y, end_x, end_y)+matrix[y][x],
        min_cost(z, x-1, y, end_x, end_y)+matrix[y][x],
        min_cost(z, x, y+1, end_x, end_y)+matrix[y][x],
        min_cost(z, x, y-1, end_x, end_y)+matrix[y][x]
    )
    return memo[(x, y)]

matrix = input_matrix(n)

begin_coords = list(map(int, input().split()))
end_coords = list(map(int, input().split()))

print(min_cost(matrix, begin_coords[0], begin_coords[1], end_coords[0], end_coords[1]))

1 个答案:

答案 0 :(得分:0)

问题是您使用缓存不正确。请考虑以下示例,其中代码返回1而不是0

3
0 0 1
1 0 0
1 1 0
0 0
2 2

如果您尝试按照代码流程进行操作,您会发现您的算法会按以下方式搜索矩阵:

0 -> 0 -> 1 -> x
          |
1 <- 0 <- 0 -> x
|
1 -> 1 -> 0

此外,当您执行递归调用时,您在-1处设置矩阵中的值,因此当您最终达到目标时,矩阵为:

-1 -1 -1
-1 -1 -1
-1 -1 0

当然,您正在复制矩阵,但在递归调用期间,到达该点的整个路径仍然是-1

即。当您的代码找到2, 2时,它会返回01, 2上的调用尝试计算0, 2的值,但返回inf,因为左下角是-11, 3和{{ 1}}也返回1, 1。因此,对于+inf,我们会得到正确的值x=1, y=2。代码回溯,获得矩阵:

1

我们-1 -1 -1 -1 -1 -1 -1 1 0 中有1,2 -> 1。我们必须完成memo的调用,再次尝试0, 2-1, 20, 3所有这些返回0, 1,因此我们计算+inf这是正确的。

现在事情开始出错了。 0 2 -> 2处的呼叫已尝试转到0, 1,但由于该值设置为1, 1,因此返回+inf,对于所有其他递归呼叫也是如此。因此,我们将-1 设为错误

基本上,通过在递归调用期间将矩阵中的值设置为0, 1 -> 3,您可以阻止-1的递归调用向右移动并获得正确的0, 1值。

问题出现在缓存版本中,因为现在*每次返回1时,我们都会得到错误的值。如果没有缓存,代码就可以通过不来自0 1的路径到达0 1,从而发现1 1

我会使用动态编程方法而不是cachine。使用0 1 -> 1值填充矩阵。从目标位置开始并在其中放置+inf,然后按行/列计算相邻值:

0

然而,这仍然没有那么高效。如果您正确应用动态编程,最终会得到Bellman-Ford Algorithm。您的网格只是一个图表,其中每个顶点def min_cost(matrix, x, y, end_x, end_y): n = len(matrix) memo = [[float('+inf') for _ in range(n)] for _ in range(n)] memo[end_y, end_x] = 0 changed = True while changed: changed = False for x in range(n): for y in range(n): m = matrix[y][x] old_v = memo[y][x] memo[y][x] = min( memo[y][x], m + min(memo[h][k] for h in (y-1, y+1) if 0 <= h < n for k in (x-1, x+1) if 0 <= k < n) ) if memo[y][x] != old_v: changed = True return memo[y, x] 有四个外边(边框上除外)。