Let's say the placement of a tower in cell i is valid if it, together with all previously placed towers, covers all cells <= i+5. Since the range within 5 is covered by the tower at i, we can place a tower there if every cell from 0 up to i-6 is covered.
In your DP array, the value in cell i is the min total cost a valid placement of a tower in cell i.
Then, DP[i] = C[i] + min(DP[j]) for all j that cover i - range - 1 (the closest tower to the left not covered by tower i).
At the end, the answer is the minimum value of DP[i] for all the i that cover the last cell.
The tower that covers cell i can be placed in any of the 11 spots between i-5 and i+5.
I'll give a smaller example -- same concept, but each tower covers cells within 2.
input: [16, 4, 8, 12, 7, 5, 11, 12, 14, 3]
We fill out the DP array as follows:
index: value & reasoning
0: 16 (no previous towers not covered by this)
1: 4 (no previous towers not covered by this)
2: 8 (no previous towers not covered by this)
3: 12 + min(16, 4, 8) = 12 + 4 = 16
4: 7 + min(16, 4, 8, 16) = 7 + 4 = 11
5: 5 + min(16, 4, 8, 16, 11) = 5 + 4 = 9
6: 11 + min( 4, 8, 16, 11, 9) = 11 + 4 = 15
7: 12 + min( 8, 16, 11, 9, 15) = 12 + 8 = 20
8: 14 + min(16, 11, 9, 15, 20) = 14 + 9 = 23
9: 3 + min(11, 9, 15, 20, 23) = 3 + 9 = 12
Any of the last 3 cover the last spot, so the answer is min(20, 23, 12) = 12.
By tracking which mins are selected each time, we can find the selection of towers that gives us the min.
index 9: min comes from index 5
index 5: min comes from index 1
index 1: min comes from a negative index so we're done
12 comes from indices 1, 5, 9
[16, (4), 8, 12, 7, (5), 11, 12, 14, (3)]
Ruby code (read as pseudocode if you don't know Ruby)
def f(costs, range)
# the first range elements of dp are identical to costs since they don't depend on a prior tower
dp = costs[0, range + 1]
# now, for each new index, we need to add the smallest previous dp sum
# associated with a tower that covers the spot range-1 to the left.
(range + 1).upto(costs.length - 1) do |i|
left_indx_of_subrange = [0, i - (2*range + 1)].max
right_indx_of_subrange = i-1
length_of_subrange = right_indx_of_subrange - left_indx_of_subrange + 1
dp[i] = costs[i] + dp[left_indx_of_subrange, length_of_subrange].min
end
puts dp.to_s
return dp[-(range + 1), range + 1].min
end
> f([16, 4, 8, 12, 7, 5, 11, 12, 14, 3], 2)
=> 12
This code doesn't track which indices were used.
Range 5 example:
cost = [47, 30, 38, 18, 10, 26, 16, 33, 42, 13, 29, 34, 25, 35, 30, 38, 15, 15, 45, 18, 28, 19, 37, 20, 20, 12, 29, 40, 13, 30, 24, 35, 44, 38, 24, 26, 22, 46, 39, 10, 27, 40, 36, 25, 36, 40, 26, 42, 49, 12]
range = 5
optimal = 73
optimal selections in parens: [47, 30, 38, 18, (10), 26, 16, 33, 42, (13), 29, 34, 25, 35, 30, 38, 15, (15), 45, 18, 28, 19, 37, 20, 20, 12, 29, 40, (13), 30, 24, 35, 44, 38, 24, 26, 22, 46, 39, (10), 27, 40, 36, 25, 36, 40, 26, 42, 49, (12)]
DP array: [47, 30, 38, 18, 10, 26, 26, 43, 52, 23, 39, 44, 35, 45, 40, 48, 38, 38, 68, 41, 51, 54, 72, 55, 58, 50, 67, 78, 51, 71, 65, 85, 94, 88, 74, 76, 72, 97, 90, 61, 88, 101, 97, 86, 97, 101, 87, 103, 110, 73]