ACM周总结6.5

这周继续学习了线性dp,主要就是看这部分的博客,前面看的大部分都是些常见思路题,倒也不算很难,这部分和贪心差不多,自己的思考占主要部分,关键在于状态方程怎么写,但那些相对基础的没有套路的,思路还是很简单的,代码量也比前面的部分少了很多,但那些套路多,结构复杂的,实现起来就没那么简单了,但做出来之后想想,不也就那点东西嘛。

例题分析:

acwing895 最长上升子序列

题意:给定一个长度为 N的数列,求数值严格单调递增的子序列的长度最长是多少。

分析:这道题是最基础的dp,dp问题的一般解法为找出问题的状态表达与状态计算,由于题中的数列是一个一维的序列,因此我们可以用一个一维的数组dp,来进行状态表示和计算。设f[i]是以a[i]为结尾的最长上升子序列的长度,用数组a来存储给定数列,则状态转移方程为

if (a[i] > a[j]) f[i] = max(f[i], f[j] + 1);

f[j] + 1 的含义是以比 i 小的前一个数结尾的最长上升子序列加上自己( + 1) 。

acwing1017 怪盗基德的滑翔翼(既要求最长上升,也要求最长下降)

题意: 假设城市中一共有N幢建筑排成一条线,每幢建筑的高度各不相同。初始时,怪盗基德可以在任何一幢建筑的顶端。他可以选择一个方向逃跑,但是不能中途改变方向(因为中森警部会在后面追击)。因为滑翔翼动力装置受损,他只能往下滑行(即:只能从较高的建筑滑翔到较低的建筑)。他希望尽可能多地经过不同建筑的顶部,这样可以减缓下降时的冲击力,减少受伤的可能性。
求他最多可以经过多少幢不同建筑的顶部(包含初始时的建筑)。
分析: 求最长上升子序列和最长下降子序列。条件一:怪盗基德可以在任何一幢建筑的顶端。条件二:选择一个方向逃跑,但是不能中途改变方向。条件三:只能往下滑行。目标:尽可能多地经过不同建筑的顶部。由条件一可知:选择一个数。由条件二、三可知:从选择的数开始找一个下降的子序列。由目标可知:该子序列需最长。所以,由上述分析可知我们要求最长上升子序列,并且要在同一点上求最长下降子序列,由此可以得到答案。

acwing187. 导弹防御系统(用n1个最长上升子序列和n2个最长下降子序列来覆盖区间:dfs)
题意: 为了对抗附近恶意国家的威胁,R国更新了他们的导弹防御系统。 一套防御系统的导弹拦截高度要么一直 严格单调 上升要么一直 严格单调 下降。 例如,一套系统先后拦截了高度为3和高度为4的两发导弹,那么接下来该系统就只能拦截高度大于4的导弹。 给定即将袭来的一系列导弹的高度,求至少需要多少套防御系统,就可以将它们全部击落。
分析: 每个数字要不然属于上升序列,要不然属于下降序列,可以枚举每个数字属于上升还是下降序列。对于严格单调上升:从前往后扫描每一个数,对于每个数:如果现有子序列的结尾都大于等于当前数,则创建新的子序列。将当前数放到结尾小于它的最大的子序列后面。对于严格单调下降:从前往后扫描每一个数,对于每个数:如果现有子序列的结尾都小于等于当前数,则创建新的子序列。将当前数放到结尾大于它的最小的子序列后面。

acwing897.( 最长公共子序列)
题意: 给定两个长度分别为N和M的字符串A和B,求既是A的子序列又是B的子序列的字符串长度最长是多少。

分析:

其状态表示函数 f [i, j] 表示a的前 i 个字母,和 b 的前 j 个字母的最长公共子序列长度。状态计算(集合划分)分为以下四种情况:

1.a[i] 不在,b[j]不在

max = f[i - 1, j - 1]

2. a[i] 不在,b[j]在

状态转移方程看似为max = f[i - 1][j] , 但f[i - 1, j]表示的是在a的前i - 1字母中出现, 
并且在b的前j个字母中出现的最长公共子序列的长度, 此时b[j]这个字母不一定出现。
但仍可以用f[i−1][j]来表示,原因就在于条件给定的情况被包含在f[i−1][j]中,
即条件的情况是f[i−1][j]的子集,而求的是max,所以对结果不影响。

3. a[i]在,b[j]不在

同情况2, 且2、3情况是一定存在的, 所以在写代码时, 不需要有判断情况

4.a[i]在,b[j]在

max = f[i - 1][j - 1]  + 1;

如果a[i], b[j]都存在于公共子序列中,则a[i] == b[j],情况4处理时要加上if(a[i] == b[j])的判断条件。

acwing902. (最短编辑距离)
题意: 给定两个字符串A和B,现在要将A经过若干操作变为B,可进行的操作有:

删除–将字符串A中的某个字符删除。
插入–在字符串A的某个位置插入某个字符。
替换–将字符串A中的某个字符替换为另一个字符。
现在请你求出,将A变为B至少需要进行多少次操作。

分析:首先确定状态,定义一个二维的dp数组dp[i][j]表示的是字符串a前1到i个字符和字符串b前1到j个字符使得a和b匹配的最小操作次数。题目中说可以利用增删改这三种操作,每操作一下操作次数就要加一。第二步我们写出状态转移方程,先来看删除假设我们删除a串中最后一个字母使得与b串相互匹配,那就可以推出这样一个方程dp[i-1][j]+1。再来看增加操作,假设我们要在a字符串最后一个地方增加,那就要保证字符串b中前j-1个字符串能够匹配的上,这样我们就可以推出第二个方程dp[i][j-1]+1。再来看改的操作,假设我们要在a字符串中改的话就要保证字符串a的前i-1和字符串b的前j-1匹配然后再改,但是这里可以细分为两个方程如果a[i]=b[j]的话就不需要改,也即是dp[i][j]=min(dp[i][j],dp[i-1][j-1])如果a[i]和b[j]不相等的话就要修改也即是dp[i][j]=min(dp[i][j],dp[i-1][j-1]+1),然后取这三种之间的最小值。第三步初始化dp数组。假设a字符串为空,b字符串长度为m的话那a字符串就要经过m次增加,也即是dp[0][m]=m。假设b字符串为空的话,a字符串的长度为n那a字符串就要经过n次删除也即是dp[n][0]=n;最后一步确定遍历顺序。

 acwing898. (数字三角形)
题意:求从数字三角形顶端的第一个数字往下走到底部,按照某一条路径,沿途收集到的数字总和的最大值。

        7
      3   8
    8   1   0
  2   7   4   4
4   5   2   6   5

分析:由于每一步都有两种走法(往左下走 or 往右下走),因此如果有n行,则一共有2^(n-1)条路径。这道题有两种思考方式,一种是自顶向下,另一种是自底向上。最先想到的肯定是自顶向下,但后来一想就可以发现自底向上考虑每个数的时候就要考虑是从左下方上来的还是从右下方上来的,不管是考虑哪一个数字,它左右下方都一定没有出界,就无须判断边界了,因此这种做法比第一种代码量更少,可以少一些特殊判断,也更好写。算是个基础题吧。

总的来说这周看的题还算简单,可以发现这部分难度高的题还是很多的,要学习别人那种思考方式,自己做题做不出来,看看别人怎么想的,然后理解了感慨自己怎么想不到,都说条条大路通罗马,但有人出生就生在罗马,但别人背后的努力我们却是看不到了,所以,感叹羡慕别人清晰的做题思路的时候,好好想想自己真的努力了吗,自己也要多去思考,多去想想问题的关键。越学越感觉其实ACM是在学数学,正好想到了王鲁老师之前在专业介绍的时候说过,计算机的尽头是数学,越到后面,那些问题都是复杂的数学问题,所以这真的是考验思维。看见老师在群里发了下周要学的背包问题跟区间dp的课件,好在之前做题的时候有点接触,下周继续加油,争取可以做的更好。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我是蒸的c

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值