【算法问题】四人过桥,传递手电问题(python实现)

文章讲述了如何使用动态规划解决过河问题,指出了一般认为的贪心策略并不总是最优解,通过实例分析和代码展示了如何计算所有人过桥的最短时间。
摘要由CSDN通过智能技术生成

博客主体转载自:【算法学习】Dynamic Programming动态规划--例题的python实现_dynamic programming python-CSDN博客,选取了其中的“过河问题”部分,并在此基础上进行了少量修改。

问题描述:

在一个夜黑风高的晚上,有n(n <= 50)个小朋友在桥的这边,现在他们需要过桥,但是由于桥很窄,每次只允许不大于两人通过,他们只有一个手电筒,所以每次过桥的两个人需要把手电筒带回来,i号小朋友过桥的时间为T[i],两个人过桥的总时间为二者中时间长者。问所有小朋友过桥的总时间最短是多少。

解决思路:

我本以为这是个很简单的问题:
每次都是最快的那个人把手电筒拿回来不就最省时间吗?
N-1每个人过河1次,最快的那个人陪N-1个人过河N-1次,返回了N-2次。
花费时间是N-1个人的过河时间+ 最快的人的时间×(N-2).

然后原文也写了,这个基于贪心的第一直觉是有问题的!
其实:
有时候真的可以这样
有时候却是让最快的两个人送回手电最快。

比如有4个小朋友,过桥时间为a[1]、a[2]、a[3]、a[4](a[1]到a[4]依次增大)。
按照1,2送回手电的过桥步骤(以下简称方法1):
第一步:1和2过去,花费时间a[2],然后1回来(花费时间a[1]);
第二歩:3和4过去,花费时间a[4],然后2回来(花费时间a[2]);
第三步:1和2过去,花费时间a[2],总耗时a[1] + 3a[2] + a[4]。

按照贪心过桥步骤(以下简称方法2):
第一步:1和2过去,花费时间a[2],然后1回来(花费时间a[1]);
第三步:1和3过去,花费时间a[3],然后1回来(花费时间a[1]);
第一步:1和4过去,花费时间a[4],总耗时2a[1] + a[2] + a[3] + a[4]。

方法1的耗时减方法2的耗时: -a[1] + 2a[2] - a[3];
也就是说当 2a[2] 大于 a[1] + a[3], 就是方法2是最优解。
也就是说当 2a[2] 小于 a[1] + a[3], 就是方法1是最优解。

代码描述:

1. 每个人的耗时从小到大到排序:T[1…n]
2. 边界:
       ①  i =0: 0
       ②  i = 1: T[1]
       ③  i = 2: T[2]
3. 子问题; i 个人完成过河的最优时间opt[i]
4. 如果每个人都只和第一个人过河: opt[i] = opt[i-1]+T[1]+T[i]
5. 如果送手电的还包括第二个人:opt[i] = opt[i-2]+T[1]+T[i]+T[2]+T[2]
    即所谓的河这边剩两人,其中一个肯定是T[2]
    正是因为
    T[2]送回手电+T[1]T[2]过河的时间< T[1]送手电+T[1]陪最后一个人过河的时间
    才会有这种情况的存在
6. 最优解:4,5的较小值

代码:

def solution(time,N):
    def cal_opt(time,N,opt):
        opt[1] = time[0]
        opt[2] = time[1]
        # 子问题规模3~N
        for i in range(3,N+1):
            # 子问题求最优
            sum_1 = opt[i-1]+time[0]+time[i-1]
            sum_2 = opt[i-2]+time[0]+time[i-1]+time[1]+time[1]
            opt[i] = min(sum_1,sum_2)
        return opt
    # 边界直接返回
    if N ==0:
        return 0
    if N == 1:
        return time[0]
    if N == 2:
        return time[1]
    # 初始状态
    opt = [0 for i in range(N+1)]
    opt = cal_opt(time,N,opt)
    return opt[N]

time = [1,2,5,10]
time = sorted(time)
print(solution(time,len(time)))

代码解释:

        最后的 opt,它是一个列表,用于存储每个子问题的最优解。在函数开始时初始化为全零列表,并在计算过程中逐步填充。返回时,取出 opt[N] 即可得到问题规模为 N 的最优解。

结果:

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值