python练习题(四)——跳跃方格求最短时间

系列文章目录

python练习题(一)——A+B Problem

python练习题(二)——Words

python练习题(三)——Consecutive Integer



前言

本题是一位德国的学生问我朋友的一道题,感觉还是挺有意思的,自我感觉是一个有难度的题


一、题目描述

我们考虑在一系列 n方块上玩以下游戏。玩家从第 0 格开始,必须通过几次跳跃才能到达 n − 1 格。以下规则适用:

– 第一次跳跃总是从方格 0 到方格 1。

– 向前跳跃总是比前一次跳跃长一个(如果最后一次跳跃跳过了i方块,现在是i+1)。

– 向后跳跃总是与前一次跳跃一样长。

– 玩家不得跳到空间 i < 0 或 i >n − 1。

例如,在第一次从方格 0 跳到方格 1 之后,玩家可以从方格 1 向前跳到方格 3 或返回方格 0。在后一种情况下,接下来的向前跳跃将到達方格 2。如果玩家降落在一个方塊i上,他们首先必须在下一次跳跃之前等待一定的时间n(我们在这个问题中忽略了跳跃本身的时间)。计算到达方塊 n − 1 的最短时间。

此处给出了此实例从字段 0 到字段 4 的最佳时间为 2 + 5 + 2 + 4 = 13 的示例路径(最后一个字段的等待时间也计算在内):

 此处给出了此实例从字段 0 到字段 4 的最佳时间为 2 + 5 + 2 + 4 = 13 的示例路径(最后一个字段的等待时间也计算在内)

题目要求:

本题需要解决两个问题,首先证明玩家总能到达方格 n − 1,给出一个递归方程来解决这个问题。其次,到达n-1的方式有很多种,请计算到达n-1的最短时间

二、问题分析

首先用我自己的话理解这个问题,然后确定输入输出。将每一个方格理解成一个房间,方格里面的数字是你要在房间里面待的时间。初始位置在零号房间,步长为1向前,接下来每一次向前走步长+1,回退时步长不变,如果走到尽头则从0号房间继续顺延。

输入:我要去的房间号和所有的房间时间序列

输出:所用的时间time

1、证明总能到达你想要取得房间

对于n的房间,玩家总能可以通过以下策略来到达自己想要去的位置:

0→1→0→2→0→3→⋯→0→n−1

在逻辑上讲,这种方式总是能够达到目的的,但是显然这个策略并不总是最优的,而且在时间上也可能有更短的方式。

这种方式显然是一种动态规划,到达第哪个房间所有的时间:

dp[n]=dn[n-1]+room_list[0]+room_list[n]

因为如果是达到第n个房间,前一步肯定是从n-1个房间回到0号房间,然后再到第n个房间

输入:room_list=[3,2,1,5,4]

达到1号房间所用的时间:

0-->1    ==》time1=room_list[1]

达到2号房间所用的时间:

0-->1-->0-->2    ==》 time2=time1+room_list[0]+room_list[2]

到达3号房间所用的时间:

0-->1-->0-->2-->0-->3==》time3=time2+room_list[0]+room_list[3]

……

达到n号房间所用的时间:

0-->1-->0-->2-->0-->3……-->n-1-->0-->n==》time (n) =time( n-1)+room_list[0]+room_list[n]

2、代码实现

def func(n, room_list):
    if n <= 1:
        return room_list[1]
    return func(n - 1, room_list) + room_list[0] + room_list[n]


if __name__=='__main__':
    print(func(2,[3,2,1,5,4]))

三、最优解的存在性

显然通过上面的代码已经能够证明了,玩家是能够达到任意一个房间的,但是显然时间上并不是最优的。因为如果玩家要到3号房间,玩家可以直接从0--->1--->3,这是最贱的路径了,而不是反复横跳,最终达到目的地。最优的情况下应该怎么跳跃呢?

关于这个问题,最初想到的是动态规划,首先肯定是能做的,但是由于我资质愚钝,动态规划不太熟悉,所以最终失败了,没有找到递推方程,然后考虑了广度优先的搜索算法。

这里面做了两个假设,在这两个假设条件下即可实现了:

1、默认条件下,在没有达到指定房间的时候,玩家优先考虑往前跳,因为往前跳一次距离比较远

2、玩家如果再一次跳跃之后发现下一跳会超过房间号,那么下一跳就要放回跳

举例:

如果我要去5号房间,目前我在0号房间,默认我要优先往前跳,于是

第一次跳跃:房间1,此时我判断下一跳往前目的地是房间3,没有超过房间5,那就继续往前跳。

第二次跳跃:房间3,此时我判断下一跳往前目的地是房间房间6,超过了房间5,那就往后跳

第三次跳跃:房间1,此时我判断,下一跳的目的地是房间4,没有超过房间5,那就继续往前跳

第四次跳跃:房间4,此时物品判断下一跳的目的地是房间8,超过了房间5,那就往后跳

第五次跳跃:房间1,此时我判断下一跳的目的地是放间5,与目标一直,往前跳,结束。

用图来表示如下:

 

代码详情:

def get_min_time(n,room_list):
    target_pos=n
    pre_pos=0
    current_pos=0
    next_pos=0
    max_pos=len(room_list)-1
    i=1
    j=0
    sum_time=0
    val=0
    while True:
        next_pos+=i
        current_pos+=j
        pre_pos=current_pos-j
        if next_pos>target_pos or next_pos>max_pos:
            val=sum_time+room_list[pre_pos]+room_list[target_pos]
            break
        if next_pos==target_pos:
            val=sum_time+room_list[target_pos]
            break
        sum_time+=room_list[next_pos]
        print(sum_time)
        i+=1
        j+=1
    return val

room_list=[3,2,1,5,4]
res=get_min_time(4,room_list)
print(res)

注意:代码中需要记录当前位置、前一次跳跃位置、下一次跳跃位置,目标位置、以及房间总长度(总共多少个房间,如果房间下一跳超过了房间个数,也要往回跳)

四、分析

分析这种算法是否是最优的算法呢?恐怕不是,目前代码能通过我个人认为知识一种巧合,因为上面的逻辑并没有考虑每个房间中等待的值得大小,如果我们考虑一个极端的场景,如果某个房间的值特别大,1000000,其他房间都是1,那么这个房间肯定是一个禁着点,要想办法绕过这个房间号才对。另一种方式就可以考虑使用动态规划来实现了。我们考虑函数 f(i,j),它给出以长度为 j 的跳跃到达字段 i 的最短时间。函数 f(i,j) 可以递归地表示为f(i,j)=min(f(i−j,j−1),f(i+j,j))+ti,大佬们有别的想法可以评论区一起讨论一下。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值