我试图编写一种能够以最低成本找到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]))
答案 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
时,它会返回0
。 1, 2
上的调用尝试计算0, 2
的值,但返回inf
,因为左下角是-1
,1, 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, 2
和0, 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]
有四个外边(边框上除外)。