Start with an array A of positive numbers. Start at index 0. From index i, you can move to index i+x for any x <= A[i]. The goal is to find the minimum number of moves needed
Here's a slight modification of Ricky Bobby's answer, which I'll show to be optimal:
find_shortest_path(A):
path := [0]
last := 0
max_reachable = 0
while A[last] + last < length(A) :
next_hop := x such that max_reachable < x <= A[last] + last and last + A[x] is maximum
push(path, x)
max_reachable = A[last] + last
last := x
return path
proof of correctness: I'll use induction the nodes of the path created by my algorithm.
the property I'll show is P(i) = the ith node of my path has a 'reach' no smaller than the ith node of any optimal path
where reach is defined as the number of the highest node you can hop to from that node, or +infinity if you can get past the end of the array
P(0) is obvious.
assume that P(k) is true for k >= 0
now consider the (k + 1)th node in the path created by my algorithm. Since my algorithm chose node k so that it had at least the same reach as that of the optimal path's node k, the set of nodes which may possibly be the (k + 1)th node for my algorithm is a superset of the same for any optimal path. Since my algorithm chooses the node with the greatest reach, it follows that P(K + 1) is true.
by induction, P(k) is true for all k (up to the size of the path created).
since my algorithm will end as soon as the end of the array is in reach, and this will happen no later than for any optimal path, it follows that the path created by my algorithm is optimal.
proof of optimality: each cell of the array is considered at most once, so it's O(n), which is asymptotically optimal. I don't think it's possible to design an algorithm which checks fewer cells in every case.