蓝桥杯训练——旅行家预算(贪心算法)

问题描述

一个旅行家想驾驶汽车以最少的费用从一个城市 到另一个城市(假设出发时油箱是空的)。给定两个城市之间的距离D1、汽车油箱的容量C(以升为单位)、每升汽油能行驶的距离D2、出发点每升汽油价格P 和沿途油站数N(N可以为零),油站i离出发点的距离Di、每升汽油价格Pi(i=1,2,……N)。计算结果四舍五入至小数点后两位。如果无法到达目的 地,则输出“No Solution”。

输入

第一行为4个实数D1、C、D2、P与一个非负整数N;
接下来N行,每行两个实数Di、Pi。

输出

如果可以到达目的地,输出一个实数(四舍五入至小数点后两位),表示最小费用;否则输出“No Solution”(不含引号)。

输入样例

275.6 11.9 27.4 2.8 2
102.0 2.9
220.0 2.2

输出样例

26.95

思路

运用贪心的策略,尽量多加低价的油,具体策略如下。
首先处理数据,将起点和终点加入dest和price列表,这样可以统一处理,同时设置终点油价为0,这样终点就可以看做是一个普通结点。并记录最大可走距离 m a x L = C ∗ D 2 maxL = C*D2 maxL=CD2
假设当前位置为nowIndex,依次遍历所有加油站,找到一个油价比当前低的地方 i i i(由于终点油价为0,一定可以找到),然后分情况讨论:

  • i i i处于可达范围 d e s t [ i ] < = d e s t [ n o w I n d e x ] + m a x L dest[i]<=dest[nowIndex]+maxL dest[i]<=dest[nowIndex]+maxL,则直接开到 i i i位置即可。更新 n o w I n d e x nowIndex nowIndex
    i i i,并令 c o s t = c o s t + ( d e s t [ i ] − d e s t [ n o w I n d e x ] ) / D 2 ∗ p r i c e [ n o w I n d e x ] ( 正 好 开 到 i 的 价 格 ) cost = cost + (dest[i]-dest[nowIndex])/D2*price[nowIndex] (正好开到i的价格) cost=cost+(dest[i]dest[nowIndex])/D2price[nowIndex]i
  • i i i不在可达范围,则考虑中转加油站,在 [ n o w I n d e x + 1 , i − 1 ] [nowIndex+1,i-1] [nowIndex+1,i1]范围内找到一个加油站加满油可以开到 i i i。注意,这个加油站一定存在,因为我们先检查问题是否有解。寻找规则如下:在 [ n o w I n d e x + 1 , i − 1 ] [nowIndex+1,i-1] [nowIndex+1,i1]找油价最低的加油站 m i n I n d e x minIndex minIndex,若 m i n I n d e x minIndex minIndex 可达 i i i则令 n o w I n d e x = i nowIndex=i nowIndex=i并令cost增加上开到i的费用;若minIndex$ 不可达 i i i则令 n o w I n d e x = m i n I n d e x nowIndex=minIndex nowIndex=minIndex并令cost加上补满油的费用

代码

def getMin():
    D1, C, D2, P, N = map(float, input().strip().split())
    N = int(N)
    price = []
    dest = []
    for i in range(0, N):
        l, p = map(float, input().strip().split())
        dest.append(l)
        price.append(p)
    # 将首位添加进数据表,这样可以统一处理
    dest.insert(0, 0)
    dest.append(D1)
    price.insert(0, P)
    price.append(0)
    # 添加了两个数据
    N = N+2
    # 检查是否有解 若相邻两站大于maxL则无解
    maxL = D2 * C
    for i in range(1, N):
        if dest[i] - dest[i - 1] > maxL:
            print('No Solution')
            return
    cost = 0
    nowIndex = 0
    # 在maxL距离内考察,如果油价高于当前则忽略,直到找到一个油价比当前低的地方
    # 保证在到达油价低的位置时油箱为空
 	# 终点油价设置为0,所以一定会走到终点
	# 逐个考虑,所以不会遗漏
    for i in range(1, N):
        # 若在当前可达范围内找到了最近的油价低的一站,直接开过去
        if price[i] < price[nowIndex] and dest[i] <= dest[nowIndex] + maxL:
            cost = cost + (dest[i] - dest[nowIndex]) / D2 * price[nowIndex]
            nowIndex = i
        # 找到了低价但无法到达,考虑中转加油站
        # 此时显然要在当前位置加满油(可达范围油价均比当前高)
        elif price[i] < price[nowIndex] and dest[i] > dest[nowIndex] + maxL:
            # nowIndex+1 到 i-1范围油价均比当前高,且i不可达,则一定在当前加油站加满油
            cost = cost + C * price[nowIndex]
            while True:
                # 不断中转直至i可达,选择后续中最低价
                minP = price[nowIndex + 1]
                minIndex = nowIndex + 1
                # 找到后续油价最便宜的地方
                for j in range(nowIndex + 1, i):
                    if minP > price[j]:
                        minP = price[j]
                        minIndex = j
                # 通过这次中介可达终点,直接计算
                if dest[minIndex] + maxL >= dest[i]:
                    cost += (dest[i] - dest[nowIndex] - maxL) / D2 * price[minIndex]
                    nowIndex = i
                    break
                else:
                    # 不可达到终点,补满油继续找后续最低价
                    cost += (dest[minIndex] - dest[nowIndex]) / D2 * price[minIndex]
                    nowIndex = minIndex
    return cost
print('%.2f'%getMin())

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值