蓝桥杯练习-3.17

蓝桥杯练习-3.17

代码练习

• 旅行家的预算-贪心

问题描述

一个旅行家想驾驶汽车以最少的费用从一个城市到另一个城市(假设出发时油箱是空的)。给定两个城市之间的距离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

思路:

本题事宜用贪心的思想解决,即每一步都要找到局部最优解。

策略:① 我们首先讨论那些没有解决方案的,即只要任有两个加油站的距离大于(汽车油箱的容量C * 每升汽油能行驶的距离D2),那么就是不能到达目的地的。

② 接下来就用while循环,当旅行家的走的路程等于D1时,退出,在循环中,我们先总是找出当前站点后面的最便宜的油价站点,然后结束的时候到达那个站点,如果后面的最便宜油价Pmin(站点为ii)比之前的最便宜油价P还便宜,那么我们直接加到油可以恰好到达站点ii的油,如果后面没有比当前最便宜油价还便宜的站点,(1)在这个目前最便宜的站点,就算加满油也无法到达终点,我们就直接加满油(达到局部最优,这是目前最优的策略,用最少的钱买油)(因为循环是从起始点油价开始的缘故,P永远是现在最便宜的油价,而且每个循环,旅行家一定是在某个站点考虑这个问题,所以每次循环要结束了,就得将旅行家走的路程换成当前该站点的路程) (2)加满油可以到达终点,直接加到刚好到达终点的油,然后退出

每次循环结束前都得将油量减去到达ii站点的油量,因为符合上面任何一个条件的话,因为钱已经加了,所以旅行家已经到要去if要去的地方了。

每一次都要实现局部最优,就算后面油价比现在的还贵,因为我一次性不能去终点,我只能先去后面最便宜的站点补给

代码

#include <bits/stdc++.h>
#include <cstdio>
using namespace std;
double D[10],pi[10];
int main()
{
    double D1, C, D2, P, L, d0, pz, Pmin = 1000;//D1表示两个城市之间的距离,C表示汽车油箱的容量,d0表示旅行家走过的路程
    int N;//D2表示每升汽油能行驶的距离,P表示出发点汽油价格,N表示沿途油站数,L是目前油箱中油的数量,pz表示旅行家花的钱
    cin >> D1 >> C >> D2 >> P >> N;
    D[0] = 0;//没有第0个油站,所以设为0,出发点
    pi[0] = P;//把出发点的油价给pi[0],P也就代表着后面每一次的最低油价,是时刻变换的,初始的时候设为出发点的油价
    d0 = 0;//初始化旅行家开始走过的路程为0
    for(int i = 1; i <= N; i++)
    {
        cin >> D[i] >> pi[i];//将沿途的油站的距离和价格记录下来
    }
    double x = D2 * C;//x为加满油能走的最大路程
    for(int i = 1; i <= N; i++)
    {
        if(D[i] - D[i - 1] > x)//如果中间有任何一个加油站的距离大于油箱加满油能走的距离,那么就是无解
        {
            printf("No Solution");
            return 0;
        }
    }
    int ii = 0;
    while(D1 - d0)//走到终点了,则D1 - d0等于0,退出循环
    {
        for(int i = ii + 1; i <= N && D1 - d0 > 0; i++)//找到之后途中油站油价最便宜的站点
        {
            if(pi[i] < Pmin)
            {
                Pmin = pi[i];
                ii = i;
            }
        }
        if(Pmin < P)//如果途径的油站的油价比这个站点(第一次是起始点的油价,后面会变)还便宜,那就在这个站点(不一定是起始点)
                    //加到使自己能刚好到达这个站点的油量
        {
            pz += ((D[ii] - d0) / D2 - L) * P;//花费的钱
            L = (D[ii] - d0) / D2;//油箱中的油
        }
        else//后面途径的油站油价都比目前最低油价的站点贵
        {
            if(D1 - d0 > x)//并且没有办法一次就到达终点,那就直接在这个最便宜的站点加满油,下一次去那个后面最便宜的站点补充
            {
                pz += (C - L) * P;
                L = C;
            }
            else//可以一次到达终点,那就加到刚好到终点的油
            {
                pz += ((D1 - d0) / D2 - L) * P;
                break;//到终点就可以break了
            }
        }
        L = L - (D[ii] - d0) / D2;//走过多少路,就相应在油箱中减去多少,每次都消耗走到下一个“最便宜”站点站点的油量
        d0 = D[ii];//更新现在旅行家的移动到了哪,每一个while循环旅行家一定会停在一个油站,看看是否需要加油或者进行其他操作
        P = Pmin;//更新当前的最低油价
        Pmin = 1000;//变成一个很大的值,方便之后比较
    }
    printf("%.2lf",pz);
    return 0;
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值