Dynamic programming
Dynamic programming
Dynamic Programming
1. Introduction to Dynamic Programming
1.1 What is Dynamic Programming?
Dynamic Programming (DP) is a method for solving complex problems by breaking
them down into simpler subproblems. It is a powerful technique that combines the
correctness of complete search and the efficiency of greedy algorithms.
Key characteristics of Dynamic Programming:
• Solves problems by combining solutions to subproblems
• Stores the results of subproblems to avoid redundant calculations
• Typically applies to optimization problems
The term "programming" in this context refers to a tabular method, not to writing
computer code.
1.2 History and Background
• Developed by Richard Bellman in the 1950s
• Originally used to solve optimization problems in economics
• Bellman's "Principle of Optimality" forms the core of dynamic programming
• Has since been applied to various fields including computer science,
operations research, and bioinformatics
1.3 Comparison with Other Algorithmic Paradigms
1. Divide and Conquer:
o Similarity: Both break problems into smaller subproblems
o Difference: DP reuses solutions to subproblems, while divide and
conquer solves each subproblem independently
2. Greedy Algorithms:
o Similarity: Both make choices at each step to find the optimal solution
o Difference: DP considers all possible choices and their future
consequences, while greedy algorithms make the locally optimal
choice without considering the future
3. Brute Force:
o Similarity: Both can potentially explore all possible solutions
o Difference: DP stores and reuses intermediate results, significantly
reducing time complexity
1.4 When to Use Dynamic Programming
Master Data Science and Artificial Intelligence Semester : S1
Course: Advanced Operation Research Prof. LAYEB
• Checks the cache before computing a result; if not found, computes and then
caches the result
Example implementation (Python):
def fibonacci(n, memo={}):
if n in memo:
return memo[n]
if n <= 1:
return n
return memo[n]
Advantages:
• Easy to implement, often just an addition to a recursive solution
• Computes only necessary subproblems
Disadvantages:
• Still uses recursive calls, which can lead to stack overflow for very large inputs
2.4 Tabulation
Tabulation is a bottom-up dynamic programming technique that involves building a
table of results for subproblems and using those results to solve larger problems.
Key points:
• "Bottom-up" because it starts with the smallest subproblems and builds up to
the main problem
• Uses an n-dimensional table to store results, where n is the number of
parameters that change in the subproblems
• Typically implemented using iteration rather than recursion
Example implementation (Python):
def fibonacci(n):
if n <= 1:
return n
dp = [0] * (n + 1)
dp[1] = 1
return dp[n]
Master Data Science and Artificial Intelligence Semester : S1
Course: Advanced Operation Research Prof. LAYEB
Advantages:
• Often more efficient in terms of space complexity
• Avoids recursive overhead and potential stack overflow issues
Disadvantages:
• May compute unnecessary subproblems
• Can be less intuitive to implement for some problems
3. Steps to Solve a DP Problem
3. At each stage, the decision made transforms the current state into a state
associated with the next stage. In this example, being in a given city, the traveler
decides to go to another city that is a state of the next step.
4. Given a state, an optimal strategy for the remaining steps is independent of the
decisions made in the previous steps.
5. The procedure for finding the optimal solution starts with finding the optimal
decision for the last step.
6. A recurrence relation that identifies the optimal strategy of step n will find the
optimal strategy d for step n+1.
The optimal strategy, given that we are in the S state of step n, requires finding the
value of xn which minimizes the above expression.
The precise form of the recursive relation differs from one problem to another.
However, a notation similar to the one introduced in the previous example is to be
used, as summarized below the notation used:
1. n = label of the current step (n = 1, 2, . . . , N ).
2. sn = current state of step n.
3. xn = decision variable of step n. xn* = optimal value of xn (knowing
sn).
4. fn(sn, xn) = contribution of steps n, n + 1, . . . , N in the objective function if
the system starts from the state sn to step n, the immediate decision is xn, and
optimal decisions are made thereafter.
f n*(sn) = fn(sn, xn*).
5. The recursive relation will always be of the form
f n*(sn) = max { fn(sn, xn)} where f n*(sn) = min {fn(sn, xn)},
xn xn
Master Data Science and Artificial Intelligence Semester : S1
Course: Advanced Operation Research Prof. LAYEB
1. Using this recurrence relationship, the algorithm proceeds step by step, starting
with the last step and working backwards to the first step. In any dynamic
programming problem, one can construct at each step an array analogous to the
next.
Stage n
fn(S, x1)
Reading the solution : the final step only leads to the (optimal) value of the initial
problem. It does not directly give the solution leading to this value. In general, to get
this solution, we do the opposite work by reading from the table starting from the final
solution and doing the opposite path of the calculations made from step 1.
Probability of failure
Number of new researchers Groups
1 2 3
0 0,4 0,6 0,8
1 0,2 0,4 0,5
2 0,15 0,2 0,3
Contribution of the xn decision is the probability that team n will fail after having xn
more seeker.
with fn(S, xn) = pn(xn) × f n*+1 (S, xn), pn(xn) is the contribution of the decision xn
and f 3* (s) =1.
S S+xn
pn(xn)
In this example the recursive relation is not additive in time, but it is a multiplication.
Stage 3
x3 0 1 2 f 3* (S) x3*
S
0 0,8 - - 0,8 0
Stage 2 f*
f2(S, x2) = p2(x2) 3 (x3)
x2 0 1 2 f 2* (S) x2*
S
0 0,48 - - 0,48 0
Stage 1
*
f1(S, x1) = p1(x1) f 2 (x1)
* * *
The optimal strategy is x1 = 1, x2 = 0 and x3 = 1.
The probability of failure of the three research groups is 0.06.
Exercise to do: Solve the backpack problem using dynamic programming
Many DP problems only require results from a limited number of previous states (e.g.,
Fibonacci, minimum path sum). By using a rolling array or a constant number of
variables, space can be reduced from O(n) or O(n^2) to O(1).
The divide and conquer with DP technique is useful for optimization problems over
ranges (such as in convex hull trick or Knuth’s optimization). By dividing the DP
Master Data Science and Artificial Intelligence Semester : S1
Course: Advanced Operation Research Prof. LAYEB
table into smaller sections, you can often reduce time complexity from O(n^2) to O(n
log n) or better.