# Introduction to Dynamic Programming

Note: this page has been created with the use of AI. Please take caution, and note that the content of this page does not necessarily reflect the opinion of Cratecode.

Dynamic programming is like your favorite superhero, swooping in to save the day when you're faced with complex optimization problems. This powerful technique combines the best of recursion and memoization to make problem-solving a breeze. So buckle up and get ready to dive into the world of dynamic programming!

## What is Dynamic Programming?

Dynamic programming (DP) is a method for solving problems by breaking them down into simpler, overlapping subproblems that can be solved independently. These subproblems are solved only once, and their solutions are stored in a table (or a cache) for future reference. This memoization technique helps avoid redundant calculations and speeds up the overall process.

The magic of dynamic programming lies in its ability to take a big, scary problem and transform it into a series of smaller, manageable subproblems. It's like solving a jigsaw puzzle: instead of trying to jam all the pieces together at once, you start with one piece and work your way through the puzzle, piece by piece.

## When to Use Dynamic Programming

Dynamic programming is particularly effective for problems that exhibit two key properties:

1. Overlapping Subproblems: The problem can be broken down into smaller subproblems that are solved independently. The solutions to these subproblems are used multiple times to solve the overall problem.
2. Optimal Substructure: The optimal solution to the problem can be constructed from the optimal solutions of its subproblems.

If a problem meets these criteria, it's prime real estate for dynamic programming!

## Common Dynamic Programming Problems

To help wrap your head around dynamic programming, let's take a look at some common problems and how DP can be utilized to solve them efficiently.

### Fibonacci Sequence

The Fibonacci sequence is a classic example of a problem with overlapping subproblems. In this sequence, each number is the sum of the two preceding ones, starting from 0 and 1. Using dynamic programming, we can calculate the nth Fibonacci number without recalculating the same values multiple times.

``````def fib(n, memo={}):
if n == 0 or n == 1:
return n

if n not in memo:
memo[n] = fib(n - 1) + fib(n - 2)

return memo[n]

print(fib(10))  # Output: 55``````

### Longest Common Subsequence

Given two sequences, the longest common subsequence (LCS) problem involves finding the longest subsequence common to both sequences. This problem can be solved using dynamic programming by constructing a table to store the lengths of the longest common subsequences for different subproblems.

``````def lcs(a, b):
m, n = len(a), len(b)
dp = [[0] * (n + 1) for _ in range(m + 1)]

for i in range(1, m + 1):
for j in range(1, n + 1):
if a[i - 1] == b[j - 1]:
dp[i][j] = dp[i - 1][j - 1] + 1
else:
dp[i][j] = max(dp[i - 1][j], dp[i][j - 1])

return dp[m][n]

a = "ABCDGH"
b = "AEDFHR"
print(lcs(a, b))  # Output: 3``````

### Knapsack Problem

The knapsack problem is an optimization problem where you're given a set of items, each with a weight and a value, and you need to determine the most valuable combination of items that can fit into a knapsack with a limited weight capacity. Dynamic programming can be used to construct a table to store the maximum value attainable for different weight capacities.

``````def knapsack(W, wt, val, n):
dp = [[0 for _ in range(W + 1)] for _ in range(n + 1)]

for i in range(n + 1):
for w in range(W + 1):
if i == 0 or w == 0:
dp[i][w] = 0
elif wt[i - 1] <= w:
dp[i][w] = max(val[i - 1] + dp[i - 1][w - wt[i - 1]], dp[i - 1][w])
else:
dp[i][w] = dp[i - 1][w]

return dp[n][W]

val = [60, 100, 120]
wt = [10, 20, 30]
W = 50
n = len(val)
print(knapsack(W, wt, val, n))  # Output: 220``````

Dynamic programming is a powerful technique with a wide range of applications. By breaking problems into simpler subproblems and storing their solutions, you can optimize your code and tackle even the most formidable challenges. So go forth and conquer the world of dynamic programming!