我需要一些帮助,以找到达到约束条件的数组末尾所需的最小跳转数。
我有20个数字组成的数组,在0-100之间随机选择。没有重复,数字按递增顺序排列。第一个数字为0,最终数字始终为100。
int data[] = {0,8,10,18,20,25,31,33,43,45,49,51,57,62,63,69,76,84,91,100}
约束1:最大跳跃不能超过10。
约束2:跳10后必须小于10,否则没有终点。
在下面的示例中,不允许0-> 10后跟10-> 20,因为它们都相距10步。
data2[] = {0,10,20,21,25,28,31,33,43,45,49,51,57,62,63,69,76,84,91,100}
我看过Minimum number of jumps to reach end | Set 2 (O(n) solution)
但是我在应用约束时遇到了麻烦。我们将不胜感激有关如何纳入约束的任何指示。
答案 0 :(得分:0)
这是Python解决方案,因为这是您最初为问题添加标签的语言之一。
这个想法是递归地尝试所有可能的路径。这在此处分为两个部分:paths
生成器产生所有可能的路径,然后我们保留最短的路径。
def paths(data, curr_path=None, next_can_be_10=True):
if curr_path is None:
curr_path = [0]
reachable = [v for v in data if curr_path[-1] < v <= curr_path[-1] + 9 + next_can_be_10] # True is 1, False is 0
if 100 in reachable:
yield curr_path + [100]
for candidate in reachable:
jump = candidate - curr_path[-1]
yield from paths(data, curr_path + [candidate], jump < 10 )
data = [0,8,10,18,20,25,31,33,43,45,49,51,57,62,63,69,76,84,91,100]
min_len = len(data)
for p in paths(data):
if len(p) < min_len:
shortest = p
min_len = len(shortest)
print(count, shortest, 'length:', min_len)
# [0, 8, 18, 25, 33, 43, 49, 57, 62, 69, 76, 84, 91, 100] length: 14
这不是针对您任务的最有效解决方案,因为您只需要返回最短路径即可在探索所有可能性时随时选择。当路径的长度大于当前最短路径的长度时,您也可以使探索短路,尝试首先跳到最大可到达数字,依此类推。但是您可以从此处提取主要思想并编写自己的解决方案。
修改
如果原始列表变长,递归会非常慢。
这是一个直接的解决方案:我们迭代所有数据值。对于每个值,我们都跟踪导致它的最短路径。实际上,我们必须跟踪一两个不同的路径:一个导致结尾值短(小于10)的值的跳转,和/或导致结尾值跳10的值的跳转。 / p>
def shortest_path(data):
# shortest_paths is a dict, with items of data as keys and whose values are
# dicts that have one or two of the keys:
# - path_for_all_jumps, the shortest path to value without a 10-jump as last
# jump, which can be reused for any further jump up to 10
# - path_for_small_jumps, a path shorter than path_for_all_jumps, but that was
# reached with a final 10-jump. So, it can't be used for a 10-jump.
shortest_paths = {data[0]: {'path_for_all_jumps': [0]}}
for value in data[1:]:
# In order to find the shortest paths up to value, we consider first
# the paths already found ending 9 or less below value.
# For each end value, we can take the shortest of path_for_all_jumps, path_for_small_jumps
previous_paths = [min(paths.values(), key=len) for prev_val, paths in shortest_paths.items()
if prev_val >= value-9]
shortest_paths[value] = {}
if previous_paths:
shortest = min(previous_paths, key=len)
# This path can be reused by any jump, as we jumped by less than 10
shortest_paths[value]['path_for_all_jumps'] = shortest + [value]
else:
# No small jump possible to value
shortest = None
# We can do a 10-jump to value if value-10 has a path for all jumps:
try:
shortest_after_10_jump = shortest_paths[value-10]['path_for_all_jumps']
if shortest is None or len(shortest_after_10_jump) < len(shortest):
# We have a better path to value, but we'll only be able to use it for small (<10)
# jumps, as we just jumped 10
shortest_paths[value]['path_for_small_jumps'] = shortest_after_10_jump + [value]
except KeyError:
# We couldn't make a 10-jump
pass
shortest = min(shortest_paths[100].values(), key=len)
return len(shortest), shortest
一些测试和计时:
data = [0,8,10,18,20,25,31,33,43,45,49,51,57,62,63,69,76,84,91,100]
print(shortest_path(data))
# 14, [0, 10, 18, 25, 33, 43, 49, 57, 62, 69, 76, 84, 91, 100]
data2 = [0, 6, 13, 20, 25, 30, 33, 36, 42, 45, 48, 53, 60, 63, 66, 69, 72, 76, 80, 83, 86, 89, 92, 95, 100]
print(shortest_path(data2))
# 14, [0, 6, 13, 20, 30, 36, 45, 53, 60, 69, 76, 83, 92, 100]
%timeit shortest_path(data2)
# 123 µs ± 939 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)