完美解决n人过桥/过河问题

简介:问题解决思路记录。

问题描述:

n个人要过一座河,只有一条船,每次最多只能通过两个人。 每个人的速度不同,若两人组队,队伍速度等于较慢一人的速度。你要做的是计算这n个人全部通过的最少时间。

 

思路:

人数小于等于3的情况比较简单,单独处理。
当人数大于3的时候,有两种方法,在介绍方法之前我们先给列表中特定的元素一个代号,假设列表从小到大排序后为list=[0,1,2,...,n] 我们令a=0号元素,b=1号元素,x=n-1号元素,y=n号元素。接下来介绍两种方法:

方法一:ab双摆渡法

 先由a、b将船开过去,然后a回来,x和y过去,再由b把船带回来。

此过程所花时间为 b+a+y+b。

方法二:a单摆渡法

由a将y和x摆渡过去,a再把船带回来。

此过程所花时间为 y+a+x+a。

这两个方法的共同点都是一次摆渡两个最大值过去,在不同的情况下这两者的优劣不同,所以要分当前情况下哪一种方案最佳就用哪一种方案。

将两者所用时间对比化简可以发现,当2b<x+a时ab双摆渡法更优,反之则使用a单摆渡法。

如此循环直到队列中人数小于等于3时分情况解决:

人数为0时表示最开始就为0,输出0。

人数为1时表示最开始就为1,输出list[0]。

人数为2时就有可能是经过上述循环的结果了,在上面消耗的总时间t上加入max(list[0],list[1])即可。

人数为3时也有可能是经过上述循环的结果了,在上面消耗的总时间t上加入sum(list)即可。这里的list中仅剩最后三个元素。

由python实现的代码如下:

# 输入
# 多组输入。每组数据的第一行是输入一个n,代表有n(1 <= n && n <= 500)个人,接下来的n个整数,代表着每个人的所需时间。
#
# 输出
# 输出一个整数,代表最优策略所需时间sum。
#
# 示例输入
# 4
# 1
# 10
# 5
# 2
#
# 示例输出
# 17
import sys
i=-1
for line in sys.stdin:
    i+=1
    if i==0:
        n=int(line.split()[0])
        arr=[]
    else:
        a=int(line.split()[0])
        arr.append(a)
        if i==n:
            arr.sort()
            break


t=0
right=[]
while(len(arr)>3):#小于等于3的情况比较简单,单独处理
    #一次摆渡过去两个最大值

    t_i = 0
    if 2*arr[1]<arr[0]+arr[-2]:#这一趟中,满足这个条件就使用a,b摆渡法,否则就使用a护送法
        right.append(arr.pop())
        t_i+=right[-1]#这是+y
        right.append(arr.pop())
        t_i +=arr[0]+ 2*arr[1]#这是+a+2b
    else:
        right.append(arr.pop())
        t_i += right[-1]#这是+y
        right.append(arr.pop())
        t_i += right[-1]#这是+x
        t_i += 2 *arr[0]  # 这是+2a
    t+=t_i
l=len(arr)
if l==0:
    print(0)
elif l==1:
    print(arr[0])
elif l==2:
    print(t+max(arr[0],arr[1]))
elif l==3:
    print(t+sum(arr))

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值