What are effective approaches for teaching dynamic programming?
I think it's really about breaking down the concepts into smaller pieces. First a student needs to understand recursion well, then they can understand memoization and dynamic programming. It's hard to just jump into  e.g. the knapsack problem without first having worked through simpler problems. After one gets practice with the basic concepts, dynamic programming isn't inherently so difficult. Here's a basic way one can break it down:


Recursion


As an alternative to loops
Binary search
Divide and conquer
Backtracking

Memoization


Backtracking can be inefficient. Why not cache the results as you go through them?
Simple problems, such as reaching a specific sum with certain coins.
Can then consider harder problems, where a 2D array is required.

Dynamic programming (DP)


Consider the coin sum problem again. How would one be solve it manually for the numbers 1 - 10? Can this "build-up" solution be put into code?
Solving more advanced problems with dynamic programming instead of recursion/memoization.
Identifying problems for DP approaches - Partially this comes with experience of solving a few different problems. But there's a standard pattern one can recognize - if a recursive solution can be used to get a solution very inefficiently (by repeatedly searching through the same subproblems), then memoization and DP can be used to make it more efficient. 



(If you're interested, I also created a free tutorial on Recursion that breaks it down as above with programming challenges.)