动态规划是一种通过将原问题分解为相对简单的子问题来求解,然后将子问题的解存储起来避免之后重复计算,并最终将子问题组合成原问题的解决方法。动态规划并不算是一种具体的算法,更应该被认为是一种解决问题的思想。
动态规划通常适用于具有重叠子问题和最优子结构性质的问题。具有重叠子问题的问题意味着在解决问题的过程中,我们需要解决相同的子问题。而最优子结构性质意味着问题的最优解可以通过其子问题的最优解来计算。
能用动态规划解决的问题,需要满足三个条件:最优子结构,无后效性和子问题重叠。
动态规划算法的具体实现方法有多种,例如自顶向下的记忆化搜索和自底向上的迭代算法。在实际应用中,动态规划可以用来解决一些经典问题,如最长公共子序列问题、背包问题和图的最短路径问题等。
本文主要举一些简单和常见的例子。
线性DP是动态规划问题中的一类问题,指状态之间有线性关系的动态规划问题。也可以是多维的线性问题。
常见问题:
#include
using namespace std;const int N = 200 + 5;
// dp 保存第 i 个数字结尾的子序列的长度
// sc 保存原始数据
// tp 保存临时序列
int dp[N], sc[N], tp[N];// 从 s 到 e 搜索 第一个 大于 tar 的元素的下标
int bin_search(const int * nums, int s, int e, int tar) {if (s > e) return 0;int l = s, r = e;while (l <= r) {int mid = (l + r) >> 1;if (nums[mid] <= tar)l = mid + 1;elser = mid - 1;}return l;
}int main() {int n;cin >> n;int idx = 0;for (int i = 0; i < n; ++i) {scanf("%d", &sc[i]);int k = bin_search(tp, 0, idx - 1, sc[i]);if (k == idx) {tp[idx++] = sc[i];} else {tp[k] = sc[i];}dp[i] = k + 1;}cout << "max=" << idx << endl;int ans[idx + 5], len = idx;for (int i = n - 1; i >= 0; --i) {if (dp[i] == len)ans[len--] = sc[i];}for (int i = 1; i <= idx; ++i) {printf("%d ", ans[i]);}
}
背包问题(Knapsack problem)是一种组合优化的NP完全问题。问题可以描述为:给定一组物品,每种物品都有自己的重量和价格,在限定的总重量内,我们如何选择,才能使得物品的总价格最高。这个问题直接看背包九讲就好了
常见问题: