5 min read•july 30, 2024
Dynamic programming is a powerful problem-solving technique that breaks complex problems into simpler subproblems. It's all about finding optimal solutions by leveraging the principle of optimality and using Bellman's equation to solve problems recursively.
In this section, we'll explore the key concepts of dynamic programming, including variables, decision variables, and problem formulation. We'll also dive into forward and backward approaches, and examine algorithms and implementation considerations for solving DP problems efficiently.
fib = [0, 1] for i in range(2, n+1): fib.append(fib[i-1] + fib[i-2]) return fib[n]
def knapsack(W, wt, val, n, memo={}): if n == 0 or W == 0: return 0 if (W, n) in memo: return memo[(W, n)] if wt[n-1] > W: result = knapsack(W, wt, val, n-1, memo) else: result = max(val[n-1] + knapsack(W-wt[n-1], wt, val, n-1, memo), knapsack(W, wt, val, n-1, memo)) memo[(W, n)] = result return result
def lcs(X, Y): m, n = len(X), len(Y) L = [[0] * (n + 1) for _ in range(m + 1)] for i in range(1, m + 1): for j in range(1, n + 1): if X[i-1] == Y[j-1]: L[i][j] = L[i-1][j-1] + 1 else: L[i][j] = max(L[i-1][j], L[i][j-1]) return L[m][n]
def matrix_chain_order(p): n = len(p) - 1 m = [[0] * n for _ in range(n)] for L in range(2, n + 1): for i in range(n - L + 1): j = i + L - 1 m[i][j] = float('inf') for k in range(i, j): q = m[i][k] + m[k+1][j] + p[i]*p[k+1]*p[j+1] if q < m[i][j]: m[i][j] = q return m[0][n-1]
def knapsack_branch_and_bound(W, wt, val, n): class Item: def __init__(self, weight, value): self.weight = weight self.value = value self.ratio = value / weight items = [Item(wt[i], val[i]) for i in range(n)] items.sort(key=lambda x: x.ratio, reverse=True) def bound(weight, value, index): if weight > W: return 0 bound_value = value j = index while j < n and weight + items[j].weight <= W: weight += items[j].weight bound_value += items[j].value j += 1 if j < n: bound_value += (W - weight) * items[j].ratio return bound_value def knapsack_recursive(weight, value, index): nonlocal max_value if index == n: max_value = max(max_value, value) return if weight + items[index].weight <= W: if bound(weight + items[index].weight, value + items[index].value, index + 1) > max_value: knapsack_recursive(weight + items[index].weight, value + items[index].value, index + 1) if bound(weight, value, index + 1) > max_value: knapsack_recursive(weight, value, index + 1) max_value = 0 knapsack_recursive(0, 0, 0) return max_value