Dynamic Programming - Decision Procedures, and Optimizations
A decision problem is essentially a problem that can be represented as a yes/no question, and an algorithm tasked with solving the problem is called a decision procedure.
An example of a decision problem would be determining if a target number can be summed up with an array of input (positive) integers.
Our problem should return yes/no, or in this case a boolean true/false. Our decision procedure will be an algorithm that will determine whether the elements in the input array can sum to our target number. We can visualize the problem as a recursive tree by checking each element of the array against the target number, with the end of our tree yielding 0 if it there is a possible combination.
We know that if we reach 0 we reach a base case where the combinations of input numbers can add up to the target number. Similarly, if we return a negative number we know that it is not possible to sum exactly to the target number.
This gives us a recursive outline:
From there we can loop through the elements and recursively subtract each element of the array until we reach a base case:
We have a recursive solution that provides us a brute force way to test every combination. This is perfect for memoization to help us avoid running through branches in our tree that have already been solved.
Memoized
We can further increase our algorithm’s complexity by returning the values used to sum to the target sum and utilizing additional data during each call.
From here we can see that there is a way for us to find the best possible combinations (i.e the shortest number of integers) that can derive our targetNum. Since our above algorithm returned early once it found any combination, we can further tweak this procedure to track an additional variable for the shortestCombination
If our canSum algorithm was an example of a decision procedure, our howSum is an example of a combination problem, and the bestSum is an optimization problem. canSum was trying to figure out whether something was simply true/false. howSum required us to track the combinations (just the first combination), and the final iteration asked us to optimize and find the shortest possible combination. Each is an example of using dynamic programming to help track and re-use values (branches) that have already been calculated and memoized.