算法学习-动态规划(二)

问题一:四维动态规划

乌龟棋:乌龟棋的棋盘是一行N个格子,每个格子上一个分数(非负整数)。棋盘第1格是唯一的起点,第N格是终点,游戏要求玩家控制一个乌龟棋子从起点出发走到终点。
在这里插入图片描述
乌龟棋中M张爬行卡片,分成4种不同的类型(M张卡片中不一定包含所有4种类型 的卡片,见样例),每种类型的卡片上分别标有1、2、3、4四个数字之一,表示使用这种卡 片后,乌龟棋子将向前爬行相应的格子数。游戏中,玩家每次需要从所有的爬行卡片中选择 一张之前没有使用过的爬行卡片,控制乌龟棋子前进相应的格子数,每张卡片只能使用一次。 游戏中,乌龟棋子自动获得起点格子的分数,并且在后续的爬行中每到达一个格子,就得到 该格子相应的分数。玩家最终游戏得分就是乌龟棋子从起点到终点过程中到过的所有格子的分数总和。很明显,用不同的爬行卡片使用顺序会使得最终游戏的得分不同。现已知棋盘上每个格子的分数和所有的爬行卡片,求得一种卡片使用顺序使得最终游戏得分最多。
例:有9个格子上的分数分别为6 10 14 2 8 8 18 5 17,有卡片1 1 1 2 3,则使用爬行卡片顺序为1,1,3,1,2,得到的分数为6+10+14+8+18+17=73。注意,由于起点是11,所以自动获得第1格的分数6。

算法伪代码

step[1-4]//存储M张牌中相应步数的卡片数

score[0][0][0][0] = A[1]//score[a][b][c][d]表示用掉a张1,b张2,c张3,d张4得到的最高得分

for a = 0 to step[1]
    for b = 0 to step[2]
        for c = 0 to step[3]
            for d = 0 to step[4]
                score[a][b][c][d] = 0
                if a > 0 score[a][b][c][d] = max(score[a - 1][b][c][d], score[a][b][c][d])
                if b > 0 score[a][b][c][d] = max(score[a][b - 1][c][d], score[a][b][c][d])
                if c > 0 score[a][b][c][d] = max(score[a][b][c - 1][d], score[a][b][c][d])
                if d > 0 score[a][b][c][d] = max(score[a][b][c][d - 1], score[a][b][c][d])
                score[a][b][c][d] += A[a * 1 + b * 2 + c * 3 + d * 4 + 1]
return score[step[1] + step[2] * 2 + step[3] * 3 + step[4] * 4 + 1]             

时间复杂度分析

准确时间和不同步数的卡片个数有关,时间复杂度是 θ ( n 4 ) \theta(n^4)

问题二:类似矩阵链乘

天灾狼群:来自东方王国的冒险家马特(Matt)遇到了了天灾狼群。有连续的N匹狼(从左到右从1到N编号)排成一排。马特必须击杀所有狼才能生存。每匹狼(第i匹狼)拥有两种属性:自身的攻击力(记作Ai),和光环攻击力(记作Bi)。一匹狼的实际攻击力是其自身的攻击力Ai加上与其相邻的两匹狼为其提供的攻击力加成(即Ai+Bi-1+Bi+1)。马特每次只能击杀一匹狼,并且在击杀时会受到等同于这匹狼实际攻击力的伤害。击杀一匹狼后,狼之间的相邻关系会发生变化,被击杀的狼相邻的两匹狼成为新的相邻关系。求得一种击杀顺序使得马特受到的总伤害最低。

算法伪代码

for i = 1 to N
    score[i][i] = A[i]

for i = 2 to N
    for j = 1 to N + 1 - i
        y = i + j - 1
        score[i][j] = 正无穷
        for k = i + 1 to j - 1
            score[i][j] = min(score[i][j], A[k] + B[k - 1] + B[k + 1] + score[i][k - 1] + score[k + 1][j])
        score[i][j] = min(score[i][j], A[i] + B[i + 1] + score[i + 1][j], A[j] + B[j - 1] + score[i][j - 1])
return score[1][N]

算法时间复杂度

O ( n 3 ) O(n^3)

问题三

Flappy Bird:Flappy Bird是一款风靡一时的休闲手机游戏。玩家需要不断控制点击手机屏幕的频率来调节小鸟的飞行高度,让小鸟顺利通过画面右方的管道缝隙。如果小鸟一不小心撞到了水管或者掉在地上的话,便宣告失败。为了简化问题,我们对游戏规则进行了简化和改编:
(1) 游戏界面是一个长为n,高为m的二维平面,其中有k个管道(忽略管道的宽度)。
(2) 小鸟始终在游戏界面内移动。小鸟从游戏界面最左边任意整数高度位置出发,到达游戏界面最右边时,游戏完成。
(3) 小鸟每个单位时间沿横坐标方向右移的距离为1,竖直移动的距离由玩家控制。如果点击屏幕,小鸟就会上升一定高度X,每个单位时间可以点击多次,效果叠加;如果不点击屏幕,小鸟就会下降一定高度Y。小鸟位于横坐标方向不同位置时,上升的高度X和下降的高度Y可能互不相同。
(4) 小鸟高度等于0或者小鸟碰到管道(管道是竖着排列的,有一个缺口可以通过小鸟)时,游 戏 失 败 。小 鸟 高 度 为m时,无法再上升。
现在,请你判断是否可以完成游戏。如果可以,求解能够完成游戏的最少点击屏幕数;否则,求解小鸟最多可以通过多少个管道缝隙。

输入格式:
输入文件名为 bird.in 。
第1 行有3 个整数n ,m ,k ,分别表示游戏界面的长度,高度和水管的数量,每两个整数之间用一个空格隔开;
接下来的n 行,每行2 个用一个空格隔开的整数X 和Y ,依次表示在横坐标位置0 ~n- 1上玩家点击屏幕后,小鸟在下一位置上升的高度X ,以及在这个位置上玩家不点击屏幕时,小鸟在下一位置下降的高度Y 。
接下来k 行,每行3 个整数P ,L ,H ,每两个整数之间用一个空格隔开。每行表示一个管道,其中P 表示管道的横坐标,L 表示此管道缝隙的下边沿高度为L ,H 表示管道缝隙上边沿的高度(输入数据保证P 各不相同,但不保证按照大小顺序给出)。

问题四

阿鲁高的阴谋:银溪镇的追随者们为阿鲁高制造了一个船,用于在海岸上扩张。在漫长的旅途中,阿鲁高必须消耗法力创造结界以存储燃料。在途中每一天,阿鲁高都可以驶到一个联盟港口骗取燃料,代价是消耗法力维持幻象。阿鲁高的目标要航行T天才能到达。由于天气和海域的不同,每天航行所需的燃料消耗也不同。每天都可以到达一个联盟港口,骗取一些燃料(也可以不去,从结界中取得燃料补充所需;注意,每天的消耗必须被满足),骗取每个单位燃料需要一定的法力消耗。如果骗取的燃料除供这一天消耗外还有剩余,则必须把它存到法力结界中,但是限于结界规模,只能把不超过V的燃料存储到结界中。在结界中存储的每个单位的燃料每天会消耗掉阿鲁高的W点法力值。为了留有足够多的法力,阿鲁高必须尽量地减少法力消耗。请你算出阿鲁高到达目标最少的法力消耗是多少。
例:总天数T== 2,结界的最大存储量V == 5,每个港口的库存A == 10,结界中每存储一单位燃料一天的法力消耗C == 5。第一天消耗燃料5,骗取每单位消耗20法力;第二天消耗燃料3,骗取每单位消耗30法力。则最优解为在第一天骗取8单位燃料,5点消耗于当天的行程,3点存储到结界中。总法力消耗为160+15==175。

输入格式:
l 第1行,四个整数,航行的天数T,结界的最大存储量V,每个港口的库存A,结界中每存储一单位燃料一天的法力消耗W。
l 第2行至第1+T行,第k+1行有两个整数,分别表示第k天的需要的燃料N[k],抢夺第k天到达的港口的每个单位燃料的法力消耗B[k]。

算法伪代码

T//航行总天数
V//结界最大储量
W//结界中存储一单位燃料消耗的法力值
A//每个港口库存
N[i]//第i填小饶的燃料
B[i]//第i天骗取单位燃料消耗的法力值
for i = 0 to min(V, A - N[1])//上界确定的原则:1.当天结束库存0<=i<=V,并且当天骗取的燃料i+N[1]<=A
    f[1][i] = (i + N[1]) * B[1] + i * W
for i = min(V, A - N[1]) + 1 to V
    f[1][i] = 正无穷//表示这种情况不可能出现

for i = 2 to (T - 1)//从第二天到第(T - 1)天
    for j = 0 to V//第i天结束之后的库存
        f[i][j] = 正无穷
        for k = max(0, j + N[i] - V) to min(A, j + N[i])//第i天可以骗取的燃料数
            f[i][j] = min(f[i][j], k * B[k] + f[i - 1][j + N[i] - k] + j * W)//求第i天结束之后库存是j的最小法力消耗
            //(包括当天燃料存储的法力消耗
f[T][0] = 正无穷
for k = max(0, N[T] - V) to min(A, N[T])
    f[T][0] = min(f[T][0], k * B[k] + f[T - 1][N[T] - k])
return f[T][0]

问题五

正整数n 可以拆分成若干个正整数之和,考虑拆分方案的个数。
(1) 令g(i,j)表示拆分整数i时最大加数不超过j的方案个数, 证明:g(i,j)=g(i,j-1)+g(i-j,j)。
(2)根据(1)设计动态规划算法计算整数n的拆分方案个数,要求算法的时间复杂度为O(n2)
证明

  • 当j > i 时,g( i, j) = g(i, i)
  • 当j = i 时,g(i, j)= g(i, j - 1) + 1
  • 当j < i 时
    • 对i 的划分都是小于j 的,此时,g(i, j) = g(i, j - 1)
    • 对i 的划分中存在一个是等于j 的,此时,对剩余的i - j的划分也是小于等于j的, 此时,g(i, j) = g(i - j,j)
      ** 综上**,g(i, j) = g(i, j - 1) + g(i - j, j)

算法伪代码

for stp = 1 to j
    g[1][stp] = 1

for a = 2 to i
    g[a][1] = 1
    for b = 2 to min(a - 1, j)
        g[a][b] = g[a][b - 1] + g[a - b][b]
    for b = min(a - 1, j) + 1 to j
        g[a][b] = g[a][a - 1] + 1
if return g[i][j]
算法时间复杂度满足要求

问题五

设R(X)表示将整数X 的各个数位取逆序后得到的整数,如R(123)=321, R(120)=21。现输入正整数N,试设计一个动态规划算法计算方程R(X)+X=N的解的个数,分析算法的时间复杂度。

问题六

输入数组A[0:n]和正实数d,试设计一个动态规划算法输出A[0:n]的一个最长子序列,使得子序列中相继元素之差的绝对值不超过d。分析算法的时间复杂度。

发布了13 篇原创文章 · 获赞 2 · 访问量 580

猜你喜欢

转载自blog.csdn.net/qq_43887432/article/details/105102641
今日推荐