随笔 - 164  文章 - 0  评论 - 4  阅读 - 9887

动态规划基础

动态规划

入门问题探讨

题目传送门: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),开一个统计数组c[n][m](0)

状态转移方程,对所有的1in,1jm

c[i][j]={c[i1][j1]+1,if s[i]==t[j]max(c[i1][j],c[i][j1]),if s[i]!=t[j]

最后的答案即为c[n][m]
时间复杂度为O(nm)
空间可以通过滚动数组优化为 O(2max(m,n)) ?


最长上升子序列 LIS

LIS 模板题: 洛谷 B3637 最长上升子序列

O(n2) 求法

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 ;
}

O(nlogn) 做法
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 ;
}

相关资料
最长上升子序列的求法:我是链接

相关资料


例题

综合运用

小难,需要转换思维
O(n2) 过不了嗷!!! 因为题目具有特殊性,还是个诈骗题。。。但是有意思,再理解理解

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 ;
}

洛谷的该题有两问
第一问,即为求最长不下降子序列的长度
显然,类似于最长上升子序列的求法,nlogn 的做法即可

第二问,求需要的最少的导弹系统
法一 - 贪心二分维护导弹系统
法二 - 转化问题为求最长上升子序列

Qiansui_code

2023ACM暑假训练day 4 简单DP

2023ACM暑假训练day 11 动态规划

atc Educational DP Contest

posted on   Qiansui  阅读(20)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
历史上的今天:
2022-07-10 这里是浅碎呀!!!
< 2025年3月 >
23 24 25 26 27 28 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 27 28 29
30 31 1 2 3 4 5

点击右上角即可分享
微信分享提示