国科大计算机算法分析与设计2——动态规划算法

写在前面

国科大计算机算法分析与设计中动态规划算法部分,主要是一些作业题。这些题目也是动态规划方面比较经典的题目。记得上课的时候老师讲动态规划的核心就是一个多步决策过程,当时是以炮弹打飞机举例,是军事上的一个真实案例,炮弹的数量是有限的,飞机是一架一架飞的,飞机的类型不同,需要的炮弹和收益是不一样的,每一步需要决策是打还是不打。现在想想,这不是和背包问题很像吗,这个是20世纪50年代的现实问题,自此动态规划算法得到了充分的发展。
很多地方会讲动态规划最重要的是状态转移方程,确实是这样的,但是怎么想出状态转移方程呢,这个就是涉及动态规划的本质——多步决策过程,模拟成多步决策过程,比较容易找到状态转移方程。

作业1:抢劫房子得到最大收益

抢劫犯抢房子,每个房子有固定的金额,抢劫犯不能连续抢劫两栋相邻的房子,求抢劫犯可能抢到的最高总金额。假设房子之间是成直线排列的。
解法:这个问题就是一个典型的多步决策问题,每次到一个房间,只需要决定拿还是不拿。二选一的决策。如果拿的话,隔壁房间的就不能拿,否则会触发警报,不满足约束条件;如果选择不拿,就会来到下一个房间继续进行决策,拿还是不拿。
为了分析问题,我们定义一下房间顺序,假设有n个房间,编号分别为1到n,为了叙述方便,假设从最后一个房间决定拿还是不拿,依次向前。第k个房间的钱定义为 a [ k ] a[k] a[k],前k个房间能偷到的最大钱数定义为 v a l u e [ k ] value[k] value[k]。如果拿了第n个房间的钱,那就拿不了第n-1个房间的钱,但是总钱数上会加上第n个房间的钱。也即是:
v a l u e [ n ] = v a l u e [ n − 2 ] + a [ n ] value[n]=value[n-2]+a[n] value[n]=value[n2]+a[n]
如果没有拿第n个房间的前,那么就到第n-1个房间决定拿不拿。也即是:
v a l u e [ n ] = v a l u e [ n − 1 ] value[n]=value[n-1] value[n]=value[n1]
为了拿到最多的钱,只需要上面两种情况取最大值:
v a l u e [ n ] = m a x { v a l u e [ n − 2 ] + a [ n ] , v a l u e [ n − 1 ] } value[n]=max\left\{value[n-2]+a[n],value[n-1] \right\} value[n]=max{value[n2]+a[n],value[n1]}
在这里插入图片描述
在这里插入图片描述
如果房子之间的排列是一个环,不是一条直线,那么只需要破环转线就行,考虑1到n-1和2到n这两种情况,这两种情况取最大值即可,最大值就是成环的时候,能够抢到的最多钱。

作业2:丑数

给定整数n,找出并返回第n个丑数。丑数是只包含质因数2、3、5的正整数。
解法:第n个丑数一定是第1个到第n-1个丑数中的某个数乘上2、3或5得到的。
定义p2p3p5三个指针,表示下一个丑数是当前指针指向的丑数乘以对应的质因数。OPT[i],表示第i个丑数,每次决策下一个丑数是由p2p3p5中的哪个指针指向的丑数乘得。更新相应指针。
在这里插入图片描述
在这里插入图片描述

作业3:二叉搜索树个数

给定一个整数 n,求以 1 … n 为节点组成的二叉搜索树有多少种?
输 入:数字n。
输 出:二叉搜索树的数目。
在这里插入图片描述
解答: 对于以1~n为节点值组成的二叉树中,1~n每个数都可以作为根节点的节点值,当以i作为根节点时,1~(i-1) 这些数位于根节点的左子树中,(i+1)~n这些数位于根节点的右子节点中,即当以i作为根节点时有2个子问题,而1~n每个数都可以作为根节点的节点值,所以总共有2n个子问题。
以(i+1)~n为节点组成二叉搜索树的数目等于以1~(n-i)为节点组成二叉搜索树的数目。
在这里插入图片描述

在这里插入图片描述

作业4:最大整除子集

给定一个正整数数组,找其中最大的一个子集,要求该集合中任意两个元素都能整除
输 入:正整数数组
输 出:符合条件的最大子集长度
解法:如果已存在某个整除子集,若新的元素可以整除该子集中的最大值,则可加入该子集。
OPT[i],表示包含第i个元素的最大整除子集的长度
决策已存在的子集能否加入第i个元素
在这里插入图片描述

作业5:目标和

给定一个非负整数数组,a1, a2, …, an, 和一个目标数 S。现在有两个符号 + 和 – ,并且对于数组中的任意一个整数,你都可以从 + 和 – 中选择一个符号添加在前面。返回可以使最终数组和为目标数 S 的所有添加符号的方法数。
在这里插入图片描述
可以看到这些数值都是正整数,需要给这些正整数添加正负号,使得结果等于target,每个正整数都只有两种情况,要么是正号,要么是负号,这和背包问题很像。因为直接求解会有负数的情况产生,因此可以把问题变形一下,也能降低复杂度,我们假设加负号的所有正整数的和为 s u m n e g sum_{neg} sumneg,假设所有的正整数的和为 s u m sum sum,那么就可以得到 ( s u m − s u m n e g ) − s u m n e g = t a r g e t (sum-sum_{neg})-sum_{neg}=target (sumsumneg)sumneg=target,由此可得 s u m n e g = s u m − t a r g e t 2 sum_{neg}=\frac{sum-target}{2} sumneg=2sumtarget。原问题可以转化为我们选哪些数当作加负号的,没选中的就代表加了正数,因此就变成了选不选每个数,也就是说对于每个正整数,有两个选择,一个是选,一个是不选。这就和背包问题很像了,可以建立一个二维的数组 d p [ ] [ ] dp[][] dp[][],在行方向就代表了每一个数,长度就是输入数组的长度 n u m s . l e n g t h ( ) nums.length() nums.length(),在列的方向就是要计算出的目标值 s u m n e g sum_{neg} sumneg,最后一个元素 d p [ n u m s . l e n g t h ( ) ] [ s u m n e g ] dp[nums.length()][sum_{neg}] dp[nums.length()][sumneg]代表了在有 n u m s . l e n g t h ( ) nums.length() nums.length()个元素的情况下,计算出目标值等于 s u m n e g sum_{neg} sumneg的情况有多少种。
以数组中第k个元素为例,第k个元素的值就是 n u m s [ k ] nums[k] nums[k],我们假设要计算 d p [ k ] [ j ] dp[k][j] dp[k][j],也就是在k个元素的情况下,等于j的情况数有多少种,这里对于第k个元素有两种情况,选还是不选。这里分情况讨论:
(1)当 j < n u m s [ k ] j<nums[k] j<nums[k],也就是说要找的这个目标值比第k个元素小,那第k个元素肯定不能选,因为选了第k个元素就大于了目标值j,不满足要求,所以在这种情况下,第k个元素不选。不选第k个元素,就是前k个元素产生的等于j的情况数是和前k-1个元素产生的等于j的情况数相等。那么就是:
d p [ k ] [ j ] = d p [ k − 1 ] [ j ] dp[k][j]=dp[k-1][j] dp[k][j]=dp[k1][j]
(2)当 j > = n u m s [ k ] j>=nums[k] j>=nums[k],这里对于第k个元素就有两种情况,选还是不选。如果选第k个元素,那就是说前k-1个元素加一起的值是 j − n u m s [ k ] j-nums[k] jnums[k],那么在选第k个元素的情况下,有 d p [ k − 1 ] [ j − n u m s [ k ] ] dp[k-1][j-nums[k]] dp[k1][jnums[k]]这么多种情况;另一种就是不选第k个元素,不选第k个元素,那就是说前k-1个元素加一起的值是 j j j,那么在不选第k个元素的情况下,有 d p [ k − 1 ] [ j ] dp[k-1][j] dp[k1][j]这么多种情况。因为最终是问总的情况数,选和不选都算情况数,所以两个情况应该是相加的。也就是:
d p [ k ] [ j ] = d p [ k − 1 ] [ j ] + d p [ k − 1 ] [ j − n u m s [ k ] ] dp[k][j]=dp[k-1][j]+dp[k-1][j-nums[k]] dp[k][j]=dp[k1][j]+dp[k1][jnums[k]]
在这里插入图片描述

作业6:带冷冻期的股票交易

给定一个整数数组,其中第 i 个元素代表了第 i 天的股票价格 。设计一个算法计算出最大利润。在满足以下约束条件下,你可以尽可能地完成更多的交易(多次买卖一支股票):
• 你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
• 卖出股票后,你无法在第二天买入股票 (即冷冻期为 1 天)。
示例:
输入: [1,2,3,0,2]
输出: 3
解释: 对应的交易状态为: [买入, 卖出, 冷冻期, 买入, 卖出]
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
(来源:https://www.programmercarl.com/0309.%E6%9C%80%E4%BD%B3%E4%B9%B0%E5%8D%96%E8%82%A1%E7%A5%A8%E6%97%B6%E6%9C%BA%E5%90%AB%E5%86%B7%E5%86%BB%E6%9C%9F.html)

作业7:回文子串数目

给定一个字符串,计算这个字符串中有多少个回文子串。具有不同开 始位置或结束位置的子串,即使是由相同的字符组成,也会被视作不 同的子串。
示例:
输入:“abc”
输出:3
解释:三个回文子串: “a”, “b”, “c”
在这里插入图片描述

作业8:最小编辑距离

给你两个单词 word1 和 word2,请你计算出将 word1 转换成 word2 所 使用的最少操作数 。(插入、删除、替换)
示例:
Input: word1 = “horse”, word2 = “ros”
Output: 3
Explanation:
horse -> rorse (replace ‘h’ with ‘r’)
rorse -> rose (remove ‘r’)
rose -> ros (remove ‘e’)
我们需要运用题目中的三种操作来把word1转换成word2。首先,分析一下这3种操作。假设给定A,B两个单词,那对于A,B来说,只需要在A上进行操作,最终让A=B即可。我们用D[i][j]来表示A的前i个字母和B前J个字母之间的编辑距离,当我们想获得D[i][j]时,我们可以利用上述三种操作实现A=B。
1.在D[i-1][j]的基础上(此时已经知道A[:i-1]=B[:j]),所以在A中删除最后一个元素即可。
2.在D[i][j-1]的基础上(此时A[:i]=B[:j-1]),所以在A上插入B[j]即可
3.在D[i-1][j-1]的基础上(此时A[:i-1]=B[:j-1]]),所以把A[i]修改成B[j]即可,但注意如果A[i]=B[j],我们不需要做任何操作。
在这里插入图片描述

        for i in range(1, n + 1):
            for j in range(1, m + 1):
                left = D[i - 1][j] + 1
                down = D[i][j - 1] + 1
                left_down = D[i - 1][j - 1] 
                if word1[i - 1] != word2[j - 1]:
                    left_down += 1
                D[i][j] = min(left, down, left_down)
        
        return D[n][m]

(来源:https://blog.csdn.net/litt1e/article/details/105344345)
参考:算法课动态规划答疑ppt

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
国科大算法设计分析相关1-5章复习题 第一章样例: 1.讲义习题一: 第1(执行步改为关键操作数)、第2、3、6、7题 习题一 1答:执行步4pmn+3pm+2m+1;关键操作2n*m*p 2方法一答:2n-2次 方法二答:2n-2次 3 1)证明:任给c,n>c,则10n2>cn 。不存在c使10n22c时,logn>c,从而n2logn>=cn2,同上。 6 答:logn,n2/3,20n,4n2,3n,n! 7 答:1)6+n 2) 3)任意n 2.讲义习题二:第5题。 答:c、e是割点。每点的DFN、L值:A1,1、B2,1、C3,1、D4,4、E5,1、F6,5、G7,5。最大连通分支CD、EFG、ABCE。 3.考虑下述选择排序算法: 输入:n个不等的整数的数组A[1..n] 输出:按递增次序排序的A For i:=1 to n-1 For j:=i+1 to n If A[j]<A[i] then A[i] A[j] 问:(1)最坏情况下做多少次比较运算?答1+2+..+n-1=n(n-1)/2 (2)最坏情况下做多少次交换运算?在什么输入时发生? n(n-1)/2,每次比较都交换,交换次数n(n-1)/2。 4.考虑下面的每对函数f(n)和g(n) ,比较他们的阶。 (1) f(n)=(n2-n)/2, g(n)=6n (2)f(n)=n+2 , g(n)=n2 (3)f(n)=n+nlogn, g(n)=n (4)f(n)=log(n!), g(n)= 答:(1)g(n)=O(f(n)) (2)f(n)=O(g(n) (3)f(n)=O(g(n) (4)f(n)=O(g(n) 5.在表中填入true或false . 答案: f(n) g(n) f(n)=O(g(n) f(n)=(g(n)) f(n)=(g(n)) 1 2n3+3n 100n2+2n+100 F T F 2 50n+logn 10n+loglogn T T T 3 50nlogn 10nloglogn F T F 4 logn Log2n T F F 5 n! 5n F T F 6.用迭代法求解下列递推方程: (1) (2) ,n=2k 答:(1)T(n)=T(n-1)+n-1=T(n-2)+n-2+n-1 =…=T(1)+1+2+…+n-1=n(n-1)/2=O(n2) (2)T(n)=2T(n/2)+n-1=2(2T(n/4)+n/2-1)+n-1 =4T(n/4)+n-2+n-1=4(2T(n/23)+n/4-1)+n-2+n-1 =23T(n/23)+n-4+n-2+n-1

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值