代价函数变化的 Dijkstra 算法
Djikstra's algorithm with change in cost function
我面临以下编码挑战问题:
"你在 NxN 山区的起始位置 [0, 0],你只能在四个主要方向之一(即北、东、南、西)中移动。Return 最小到目标位置 [N-1, N-1] 的爬升轮数。相邻位置之间的爬升轮数定义为位置高度差(上升或下降)。
位置高度定义为整数 (0-9)。"
例如,
的结果
"010",
"010",
"010"
将是 2,因为我们在 [0,1] 中从 0 上升到 1,在 [2,2] 中我们从 1 下降到 0。我的想法是实现 Dijkstra 算法,改变代价函数。距离将给出为:
distance_current_vertex_to_0 + delta_next_vertex_to_current_vertex
但是,我的实现有问题,因为我总是得到局部最优值而不是全局最优值。例如
"9589747",
"9141279",
"2915307",
"5271413",
"8795390",
"1251866",
"4697825"
应该 return 26,但我的代码实现得到 30。所以我的问题是:我的 Djikstra 算法版本有什么不正确的地方?我从 this explanation video. The coding question comes from: here.
中激励自己
我的代码:
from copy import deepcopy
import numpy as np
def search_neighbours(pos, vv, min_distances, nearest_neighbors, m):
pos_id = int(pos[0] * len(m) + pos[1])
sorted_neighbours = {}
#for the current vertex, examine it's unvisited vertices
for key, comb in enumerate([[1, 0], [0, 1], [0, -1], [-1, 0]]):
i = comb[0]
j = comb[1]
next_pos = [pos[0] + i, pos[1] + j]
next_pos_id = int(next_pos[0] * len(m) + next_pos[1])
if 0 <= next_pos[0] < len(m) and 0 <= next_pos[1] < len(m):
#if the calculated distance of a vertex ist less than the known distance, update the shortest distance
d = min_distances[pos[0]][pos[1]] + abs(int(m[next_pos[0]][next_pos[1]]) - int(m[pos[0]][pos[1]]))
if d < min_distances[next_pos[0]][next_pos[1]]:
min_distances[next_pos[0]][next_pos[1]] = d
#update the previous vertex for each of the updated distances
nearest_neighbors[next_pos[0]][next_pos[1]] = pos
if next_pos_id not in vv:
sorted_neighbours[tuple(comb)] = abs(int(m[next_pos[0]][next_pos[1]]) - int(m[pos[0]][pos[1]]))
sorted_neighbours = {k: v for k, v in sorted(sorted_neighbours.items(), key=lambda item: item[1])}
#add the current vertex to the list of vertices
vv.append(pos_id)
#visit the unvisited vertex with the smallest distance from the start vertex
if pos == [len(m) - 1, len(m) - 1]:
return True
else:
k = 0
while k < len(sorted_neighbours.keys()):
dir = list(sorted_neighbours.keys())[k]
next_pos = [pos[0] + dir[0], pos[1] + dir[1]]
if not search_neighbours(next_pos, vv, min_distances, nearest_neighbors, m):
k += 1
else:
return True
return False #in this case ended somewhere else on the map and don't want that
def path_finder(m):
print(m)
m = m.split("\n")
pos = [0, 0]
vv = [] # visited vertices
min_distances = [[99 for _ in range(len(m))] for _ in range(len(m))]
min_distances[0][0] = 0
nearest_neighbors = [[0 for _ in range(len(m))] for _ in range(len(m))]
nearest_neighbors[0][0] = [0,0]
search_neighbours(pos, vv, min_distances, nearest_neighbors, m)
return min_distances[len(m) - 1][len(m) - 1]
m = "\n".join([
"9589747",
"9141279",
"2915307",
"5271413",
"8795390",
"1251866",
"4697825"
])
path_finder(m)
这是 Dijkstra 的样子:
def dijkstra(m):
heights = [[int(c) for c in line] for line in m.split()]
n, m = len(heights), len(heights[0])
distances = [[float('inf') for _ in range(m)] for _ in range(n)]
heap = [((0, 0, 0))] # cost so far, x, y
while heap:
prev_distance, x, y = heapq.heappop(heap)
if (x, y) == (m-1, n-1):
return prev_distance
for stepx, stepy in ((0, 1), (1, 0), (-1, 0), (0, -1)):
new_x, new_y = x + stepx, y + stepy
if not 0 <= new_x < m or not 0<= new_y < n:
continue # out of bounds, ignore
new_distance = prev_distance + abs(heights[y][x] - heights[new_y][new_x])
if new_distance < distances[new_y][new_x]: # expand
distances[new_y][new_x] = new_distance
heapq.heappush(heap, (new_distance, new_x, new_y))
return -1 # path not found
dijkstra(m)
returns 26,符合预期
我面临以下编码挑战问题:
"你在 NxN 山区的起始位置 [0, 0],你只能在四个主要方向之一(即北、东、南、西)中移动。Return 最小到目标位置 [N-1, N-1] 的爬升轮数。相邻位置之间的爬升轮数定义为位置高度差(上升或下降)。 位置高度定义为整数 (0-9)。"
例如,
的结果 "010",
"010",
"010"
将是 2,因为我们在 [0,1] 中从 0 上升到 1,在 [2,2] 中我们从 1 下降到 0。我的想法是实现 Dijkstra 算法,改变代价函数。距离将给出为:
distance_current_vertex_to_0 + delta_next_vertex_to_current_vertex
但是,我的实现有问题,因为我总是得到局部最优值而不是全局最优值。例如
"9589747",
"9141279",
"2915307",
"5271413",
"8795390",
"1251866",
"4697825"
应该 return 26,但我的代码实现得到 30。所以我的问题是:我的 Djikstra 算法版本有什么不正确的地方?我从 this explanation video. The coding question comes from: here.
中激励自己我的代码:
from copy import deepcopy
import numpy as np
def search_neighbours(pos, vv, min_distances, nearest_neighbors, m):
pos_id = int(pos[0] * len(m) + pos[1])
sorted_neighbours = {}
#for the current vertex, examine it's unvisited vertices
for key, comb in enumerate([[1, 0], [0, 1], [0, -1], [-1, 0]]):
i = comb[0]
j = comb[1]
next_pos = [pos[0] + i, pos[1] + j]
next_pos_id = int(next_pos[0] * len(m) + next_pos[1])
if 0 <= next_pos[0] < len(m) and 0 <= next_pos[1] < len(m):
#if the calculated distance of a vertex ist less than the known distance, update the shortest distance
d = min_distances[pos[0]][pos[1]] + abs(int(m[next_pos[0]][next_pos[1]]) - int(m[pos[0]][pos[1]]))
if d < min_distances[next_pos[0]][next_pos[1]]:
min_distances[next_pos[0]][next_pos[1]] = d
#update the previous vertex for each of the updated distances
nearest_neighbors[next_pos[0]][next_pos[1]] = pos
if next_pos_id not in vv:
sorted_neighbours[tuple(comb)] = abs(int(m[next_pos[0]][next_pos[1]]) - int(m[pos[0]][pos[1]]))
sorted_neighbours = {k: v for k, v in sorted(sorted_neighbours.items(), key=lambda item: item[1])}
#add the current vertex to the list of vertices
vv.append(pos_id)
#visit the unvisited vertex with the smallest distance from the start vertex
if pos == [len(m) - 1, len(m) - 1]:
return True
else:
k = 0
while k < len(sorted_neighbours.keys()):
dir = list(sorted_neighbours.keys())[k]
next_pos = [pos[0] + dir[0], pos[1] + dir[1]]
if not search_neighbours(next_pos, vv, min_distances, nearest_neighbors, m):
k += 1
else:
return True
return False #in this case ended somewhere else on the map and don't want that
def path_finder(m):
print(m)
m = m.split("\n")
pos = [0, 0]
vv = [] # visited vertices
min_distances = [[99 for _ in range(len(m))] for _ in range(len(m))]
min_distances[0][0] = 0
nearest_neighbors = [[0 for _ in range(len(m))] for _ in range(len(m))]
nearest_neighbors[0][0] = [0,0]
search_neighbours(pos, vv, min_distances, nearest_neighbors, m)
return min_distances[len(m) - 1][len(m) - 1]
m = "\n".join([
"9589747",
"9141279",
"2915307",
"5271413",
"8795390",
"1251866",
"4697825"
])
path_finder(m)
这是 Dijkstra 的样子:
def dijkstra(m):
heights = [[int(c) for c in line] for line in m.split()]
n, m = len(heights), len(heights[0])
distances = [[float('inf') for _ in range(m)] for _ in range(n)]
heap = [((0, 0, 0))] # cost so far, x, y
while heap:
prev_distance, x, y = heapq.heappop(heap)
if (x, y) == (m-1, n-1):
return prev_distance
for stepx, stepy in ((0, 1), (1, 0), (-1, 0), (0, -1)):
new_x, new_y = x + stepx, y + stepy
if not 0 <= new_x < m or not 0<= new_y < n:
continue # out of bounds, ignore
new_distance = prev_distance + abs(heights[y][x] - heights[new_y][new_x])
if new_distance < distances[new_y][new_x]: # expand
distances[new_y][new_x] = new_distance
heapq.heappush(heap, (new_distance, new_x, new_y))
return -1 # path not found
dijkstra(m)
returns 26,符合预期