This document provides an introduction to dynamic programming. It discusses how dynamic programming can be used to solve complex problems by breaking them down into smaller subproblems. It explains the two fundamental principles of dynamic programming as optimal substructure, meaning optimal solutions can be constructed from optimal solutions to subproblems, and overlapping subproblems, where the same subproblems are solved repeatedly. It describes how dynamic programming handles overlapping subproblems through memoization and tabulation and provides examples. Potential limitations and advantages of dynamic programming are also outlined.