动态规划基础
目录
动态规划
入门问题探讨
题目传送门:leetcode 198. 打家劫舍
- 自顶向下记忆化解决问题
O(n)时间
class Solution { public: int dfs(int x, vector<int> &dp, vector<int> &nums){ if(x<0) return 0; if(dp[x]!=-1) return dp[x]; else return dp[x]=max(dfs(x-1,dp,nums),dfs(x-2,dp,nums) + nums[x]); } int rob(vector<int>& nums){ int n=nums.size(); vector<int> dp( n, -1); return dfs( n-1, dp, nums); } };
- 自底而上递推解决问题
递归转递推求解
O(n)时间
class Solution { public: int rob(vector<int>& nums){ int n=nums.size(); vector<int> dp(n+2,0); for(int i=0 ; i<n ; ++i){ dp[i+2]=max(dp[i+1],dp[i]+nums[i]); } return dp[n+1]; } };
- 滚动数组优化空间
优化递推求解
O(1)空间
class Solution { public: int rob(vector<int>& nums){ int n=nums.size(); int f0=0,f1=0,f2; for(int i=0 ; i<n ; ++i){ f2=max(f1,f0+nums[i]); f0=f1; f1=f2; } return f2; } };
摘记
动态规划的两个要求:最优子结构 和 无后效性
最优子结构:大问题的(最优)解可以由小问题的(最优)解推出。注意在问题拆解过程中不能无限递归
无后效性:未来与过去无关,一旦得到了一个小问题的解,如何得到它的解的过程不影响大问题的求解。
动态规划的两个元素:状态 和 转移
状态:求解过程进行到了哪一步,可以理解为一个子问题
转移:从一个状态(小问题)的(最优)解推导出另一个状态(大问题)的(最优)解的过程
最长公共子序列 LCS
LCS模板题: 百炼oj 1458:Common Subsequence
利用动态规划求解
对于字符串s(下标1 ~ n)和t(1 ~ m),开一个统计数组
状态转移方程,对所有的
最后的答案即为
时间复杂度为
空间可以通过滚动数组优化为
最长上升子序列 LIS
LIS 模板题: 洛谷 B3637 最长上升子序列
void solve(){ int n; cin >> n; vector<int> a(n), dp(n, 1);//dp 初值为 1 int ans = 0; for(int i = 0; i < n; ++ i){ cin >> a[i]; for(int j = 0; j < i; ++ j){// 枚举之前的每一位,由前某一位dp值最大的转移过来 if(a[j] < a[i]) dp[i] = max(dp[i], dp[j] + 1); } ans = max(ans, dp[i]);// 遍历过程中取最大答案 } cout << ans << '\n'; return ; }
dp[i] 表示长为 i 的子序列的末尾最小元素为 k,每次更新可以利用二分加速
void solve(){ int n, a; cin >> n; vector<int> dp(n + 10, inf);// 初始化全部inf,代表这些位置均不可能 for(int i = 0; i < n; ++ i){ cin >> a; auto it = lower_bound(dp.begin() + 1, dp.end(), a) - dp.begin(); dp[it] = min(dp[it], a); } cout << lower_bound(dp.begin() + 1, dp.end(), inf) - dp.begin() - 1 << '\n'; return ; }
相关资料
最长上升子序列的求法:我是链接
相关资料
例题
综合运用
-
洛谷 P1255 数楼梯
此题答案过大,需要用到高精度算法 + 斐波那契数列 -
二分 + LIS - 洛谷 P1439 【模板】最长公共子序列
小难,需要转换思维
void solve(){ cin >> n; mem(b, 127); for(int i = 1; i <= n; ++ i) cin >> a, p[a] = i;//p 数组转换位置 for(int i = 1; i <= n; ++ i){ int x; cin >> x; x = p[x]; *lower_bound(b + 1, b + 1 + n, x) = x; } cout << lower_bound(b + 1, b + 1 + n, b[0]) - b - 1 << '\n'; return ; }
- 经典导弹拦截系统 洛谷 P1020 [NOIP1999 普及组] 导弹拦截
洛谷的该题有两问
第一问,即为求最长不下降子序列的长度
显然,类似于最长上升子序列的求法,
第二问,求需要的最少的导弹系统
法一 - 贪心二分维护导弹系统
法二 - 转化问题为求最长上升子序列
2023ACM暑假训练day 4 简单DP
2023ACM暑假训练day 11 动态规划
atc Educational DP Contest
本文来自博客园,作者:Qiansui,转载请注明原文链接:https://www.cnblogs.com/Qiansui/p/17539999.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
2022-07-10 这里是浅碎呀!!!