动态规划(Dynamic programming,简称 DP)是一种在数学、管理科学、计算机科学、经济学和生物信息学中使用的,通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。
动态规划常常适用于有重叠子问题和最优子结构性质的问题,动态规划方法所耗时间往往远少于朴素解法。
最长上升子序列(LIS)
给出一个序列 a1,a2,...,an−1,an ,求其最长不下降(或上升)子序列。
求最长上升子序列(LIS)的算法是Yukko介绍给我的第一个算法。
解决方案( O(n2) )
状态设计:
dp[i] 表示以第 i 个数结尾的最长上升子序列的最长长度。
状态转移方程:
dp[i]=max(dp[j])+1(1≤j<i,且a[i]>a[j])
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| #include <iostream> #include <cstdio> using namespace std; const int maxn = 100500; int n, ans; int a[maxn], dp[maxn]; int main() { scanf("%d", &n); for(int i=1; i<=n; i++) { scanf("%d", &a[i]); dp[i] = 1; } for (int i = 1; i <= n; i++) { for (int j = 1; j < i; j++) { if (a[i] > a[j] && dp[i] < dp[j] + 1) dp[i] = dp[j] + 1; } ans = max(ans, dp[i]); } printf("%d", ans); return 0; }
|
解决方案( O(nlogn) )
例题
洛谷 P1020 | [NOIP1999 普及组] 导弹拦截
洛谷 P1091 | [NOIP2004 提高组] 合唱队形
最长公共子序列(LCS)
题目描述
给出 1,2,…,n 的两个排列 P1 和 P2 ,求它们的最长公共子序列。
输入格式
第一行是一个数 n 。
接下来两行,每行为 n 个数,为自然数 1,2,…,n 的一个排列。
输出格式
一个数,即最长公共子序列的长度。
输入输出样例
输入 #1
输出 #1
数据规模与约定
- 对于 50% 的数据, n≤103 ;
- 对于 100% 的数据, n≤105 。
解决方案
状态设计:
dp[i][j] 表示 P1 前 i 位, P2 前 j 位的最长公共子序列长度。
状态转移方程:
dp[i][j]={max(dp[i][j],dp[i−1][j−1]+1)max(dp[i−1][j],dp[i][j−1])if P1[i]=P2[j]if P1[i]=P2[j]
请参阅