DP学习总结

动态规划是一种通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。 -----OI Wiki

例.1-最大子段和

分析

DP四步

⑴定义状态

定义dpi表示以i结尾的最大子段和

⑵分析答案

答案即maxdpii[1,n]

⑶分析方程

对于每个i

  1. 可以与[1,i1]的最大子段和拼接,组成新的子段和(dpi1+ai)
  2. 可以自己单独成一个子段和ai

max

⑷边界条件

dp1a1

代码实现

递归写法

定义f(i)为以i结尾的最大子段和
则递归分析即可

int f(int x){
	if(x==1){//边界条件
		return a[1];
	}
	return max(f(x-1)+a[x],a[x]);//求最大值
、}

这样时间很慢,原因是存在许多已经算过的节点被重复计算
所以用一个val记录计算过的节点信息

for(int i=1;i<=n;i++){
	dp[i]=inf;
}
int f(int x){
	if(dp[x]!=inf){
		return dp[x];//已经记录过的节点信息
	}
	if(x==1){//边界条件
		return a[1];
	}
	dp[x]=max(f(x-1)+a[x],a[x]);//求最大值
	return dp[x];
}

上述优化方法即记忆化搜索,是一种基本DP方法

记忆化搜索是一种通过记录已经遍历过的状态的信息,从而避免对同一状态重复遍历的搜索实现方式。 ------OI Wiki

转成递推形式就成了基本的线性DP

dp[1]=a[1];
for(int i=2;i<=n;i++){
	dp[i]=max(dp[i-1]+a[i],a[i]);
	maxi=max(maxi,dp[i]);
}

例.2-最长上升子序列(LIS)

分析

DP四步

⑴定义状态

定义dpi表示以i结尾的最长上升子序列长度

⑵分析答案

答案即maxdpii[1,n]

⑶分析方程

对于每个i,有若干j<iaj<ai

  1. 可以与每一个j的最长上升子序列拼接,组成新的子序列长度(dpj+1)
  2. 可以自己单独成一个子段和1

max

⑷边界条件

dpi1,因为每个dp值至少为1

代码实现

使用递推,枚举i,并且枚举j(j<i)

for(int i=1;i<=n;i++){
	dp[i]=1;
	for(int j=1;j<i;j++){
		if(a[j]<a[i]){
			dp[i]=max(dp[j]+1,dp[i]);
		}
	}
	maxi=max(maxi,dp[i]);
}

重点题-导弹拦截

50分做法

第一小问即求最长不上升子序列长度
第二问可以用Dilworth 定理解决
把序列分成不上升子序列的最少个数,等于序列的最长上升子序列长度。把序列分成不降子序列的最少个数,等于序列的最长下降子序列长度。
所以第二问等价于求最长上升子序列长度

100分做法

使用贪心优化如果,如果一个位置可以有2,3两个数选一个数,我们一定会选2,因为选2后面就有更多的机会拼接。
定义一个c数组存贮已经选了的数
只要每次二分查找第一个能够等价替换的数,就能将其替换,在过程中记录DP即可。

具体代码

补充

DP的要素:

  1. 数据范围较小
  2. 可以拆解为多个子问题
posted @   KK_SpongeBob  阅读(59)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· 本地部署 DeepSeek:小白也能轻松搞定!
· 传国玉玺易主,ai.com竟然跳转到国产AI
· 自己如何在本地电脑从零搭建DeepSeek!手把手教学,快来看看! (建议收藏)
· 我们是如何解决abp身上的几个痛点
· 如何基于DeepSeek开展AI项目
点击右上角即可分享
微信分享提示