---
id: dp
title: "Introduction to Dynamic Programming"
author: Michael Cao
prerequisites: 
 - Recursion
 - Silver - Prefix Sums
description: Speeding up naive solutions with memoization.
---

import { Problem } from "../models";

export const metadata = {
  problems: {
    usacoPast: [
      new Problem("Gold", "Hoof Paper Scissors", "694", "Easy", false, ["DP"], "dp[first i games][# changes][last gesture] -> max games won"),
      new Problem("Gold", "Time is Mooney", "993", "Easy", true, ["DP", "Graphs"], "dp[time][city] -> money"),
      new Problem("Gold", "Teamwork", "863", "Easy", false, ["DP"], "let dp[i] -> max sum of skill levels for the first i cows, then precompute subarray maximums"),
      new Problem("Gold", "Snakes", "945", "Easy", false, ["DP"], "dp[i][j] -> minimum sum of net sizes needed to catch m snakes with k changes, precompute maximums"),
      new Problem("Gold", "Circular Barn Revisited", "622", "Normal", true, ["DP", "Brute Force"], "brute force starting location, then do dp[first i positions][number of doors used][position of last door] ->  minimum distance cows need to travel"),
      new Problem("Gold", "Taming the Herd", "815", "Normal", false, ["DP"], "dp[consider first i entries only][last breakout in first i occurs at j][k breakouts among first i entries] -> # changes"),
      new Problem("Gold", "Mortal Cowmbat", "815", "Normal", true, ["DP", "Prefix Sums", "All Pairs Shortest Path"], "dp[first i letters form valid combo][last letter] -> time, Floyd Warshall on alphabet, then use prefix sums to speed up transitions."),
      new Problem("Gold", "Stamp Painting", "791", "Hard", false, ["DP"], "must be K consectutive of same color, complimetary counting for dp[up to position i][number of consecutive] -> number of ways, find closed form to reduce runtime"),
    ],
    knapsack: [
      new Problem("CSES", "Unordered Coin Change", "1635", "Intro", true, ["DP", "Knapsack"], "dp[first i coins][sum] = number of ways, order of loops is capacity then coins, remember to take MOD after every computation"),
      new Problem("CSES", "Ordered Coin Change", "1636", "Intro", true, ["DP", "Knapsack"], "dp[first i coins][sum] = number of ways, order of loops is coins then capacity, remember to take MOD after every computation"),
      new Problem("CSES", "Minimum Coins", "1634", "Intro", true, ["DP", "Knapsack"], "dp[first i coins][sum] = minimum number of coins needed"),
      new Problem("Atcoder", "Knapsack 2", "https://atcoder.jp/contests/dp/tasks/dp_e", "Easy", false, ["DP", "Knapsack"], "maximum capacity is large, and sum of values is small, so switch the states. dp[first i items][sum of values] = minimum capacity needed to achieve this sum"),
      new Problem("Gold", "Fruit Feast", "574", "Easy", false, ["DP", "Knapsack"], "dp[fullness] = whether you can achieve this fullness"),
      new Problem("Gold", "Talent Show", "839", "Hard", false, ["DP", "Knapsack", "Binary Search", "Math"], "binary search on optimal ratio, then do knapsack on weight"),
      new Problem("CF", "Round Subset", "http://codeforces.com/contest/837/problem/D", "Normal", false, ["DP", "Knapsack"], "dp[i][j][l] -> maximum amount of twos we can collect by checking first i numbers, taking j of them with total power of five equal to l"),
    ],
    pathsGrid: [
      new Problem("LC", "Longest Common Subsequence", "https://leetcode.com/problems/longest-common-subsequence/", "Intro", true, ["DP"], "dp[first i characters in first string][first j characters in second string] -> longest common subsequence, transition if s[i] = t[j] for strings s and t"),
      new Problem("HackerRank", "Edit Distance", "https://www.hackerrank.com/contests/cse-830-homework-3/challenges/edit-distance", "Intro", true, ["DP"], "dp[first i characters in first string][first j characters in second string] -> edit distance"),
      new Problem("Atcoder", "Count Paths", "https://atcoder.jp/contests/dp/tasks/dp_h", "Intro", true, ["DP"], "dp[x][y] = number of paths up to the point (x,y) in grid"),
      new Problem("Gold", "Cow Checklist", "670", "Easy", false, ["DP"], "dp[visited i Hs][visited j Gs][last cow visited on left/right] -> min energy"),
      new Problem("Gold", "Radio Contact", "598", "Easy", false, ["DP"], "dp[up to ith step of Farmer John][up to jth step of bessie] = minimum distance"),
      new Problem("Gold", "Why Did The Cow Cross the Road II", "598", "Normal", false, ["DP"], "dp[up to ith field on left side][up to jth field on right side] = maximum number of disjoint crosswalks"),
      new Problem("Old Gold", "Palindromic Paths", "553", "Hard", false, ["DP"], "start from the middle, dp[row i][row j][length] = number of strings of length 2 * length + 1 with ends at row i and j"),
    ],
    lis: [
      new Problem("LC", "Longest Increasing Subsequence", "https://leetcode.com/problems/longest-increasing-subsequence/", "Intro", true, ["DP"], "dp[i] = LIS up to i, use binary search to decrease runtime from quadratic"),
      new Problem("Old Gold", "Cowjog", "496", "Easy", false, ["DP"], "direct applicationf of longest increasing subsequence"),
      new Problem("Plat", "Sort It Out", "865", "Hard", false, ["DP"], "component of kth largest LIS, read editorial for more details"),
    ],
  }
}

Dynamic Programming is an important algorithmic technique in competitive programming which extends to even the International Olympiad of Informatics. By storing results to overlapping subproblems, Dynamic Programming optimizes the redundant computation of naive recursive solutions, massively improving computational complexity. Although it is not too difficult to grasp the general ideas behind Dynamic Programming, or DP, the technique can be used in a diverse range of problems and is a must-know idea for competitors in the USACO gold division.

<info-block title="Contest Tip">

Usually, at least one problem from every gold division contest involves some sort of DP!

</info-block>

## Tutorial

The following tutorials serve as an introduction into the mindset of DP.

 - CPH 7 
   - great introduction that covers most classical problems
 - [Topcoder DP](https://www.topcoder.com/community/competitive-programming/tutorials/dynamic-programming-from-novice-to-advanced/)
   - great for all skill levels
 - [CPC.6](https://github.com/SuprDewd/T-414-AFLV/tree/master/06_dynamic_programming)
   - examples with nonclassical problems
 - [HackerRank DP](https://www.hackerrank.com/topics/dynamic-programming)
   - also covers many classical problems

Practice makes perfect. Start by doing some classical problems (try at least one of each), as these are **must know** DP problems. Each topic starts with direct applications of the classical problems, and then some interesting variations and USACO problems which utilize the ideas. Solutions for most problems (excluding USACO) can be found on Chapter 7 of CPH.

## General

 - [**Atcoder DP Contest**](https://atcoder.jp/contests/dp/tasks)
   - very good!
 - [CSES DP Section](https://cses.fi/problemset/list/)
   - also very good!
 - [Codeforces DP Problem List](http://codeforces.com/blog/entry/325)

The following USACO problems don't fall into any of the categories below. Arranged roughly in order of difficulty. 

<info-block title="Pro Tip">

Sometimes it's a good idea to write a slower polynomial-time solution and then optimize it to the desired complexity (say, write $O(N^2)$ first and then speed it up to $O(N)$).

</info-block>

## Knapsack

<problems-list problems={metadata.problems.knapsack} />

## Paths in a Grid (and related)

<problems-list problems={metadata.problems.pathsGrid} />

## Longest Increasing Subsequence

<problems-list problems={metadata.problems.lis} />

## Other USACO Problems

<problems-list problems={metadata.problems.usacoPast} />
