【洛谷】【贪心】P1016 [NOIP1999 提高组] 旅行家的预算

题目链接:https://www.luogu.com.cn/problem/P1016

题目描述

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

输入格式

第一行,D1,CD2,PN

接下来有N行。

第i+1行,两个数字,油站i离出发点的距离Di和每升汽油价格Pi

输出格式

所需最小费用,计算结果四舍五入至小数点后两位。如果无法到达目的地,则输出“No Solution”。

测试样例

输入
275.6 11.9 27.4 2.8 2
102.0 2.9
220.0 2.2

输出
26.95

解题思路

1.枚举途中经过的加油站,每经过一个加油站,计算一次花费;

2.在一个加油站所需要加的油,就是能够支持它到达下一个油价比它低的加油站的量;

3.如果在这个加油站即使加满油,都不能到达一个比它油价低的加油站,就把油箱加满,前往能够到达的加油站中油价最低的那个;

4.如果在这个加油站即使加满油,都不能到达任意一个加油站,也不能到达终点城市,说明无解;

AC代码

#include<bits/stdc++.h>
using namespace std;

double d[10],pp[10];

int main()
{
    double d1,c,d2,p;
    int n;
    cin>>d1>>c>>d2>>p>>n;
    d[0] = 0;
    pp[0] = p;
    double dis_max = d2 * c;
    double pri_min = 505;
    double d0 = 0, l = 0, sum = 0;
    for(int i=1;i<=n;i++)
    {
        cin>>d[i]>>pp[i];
    }
    //无解的情况其实就是相邻加油站之间的距离超过了x,把无解的情况全部揪出来
    for(int i=1;i<=n;i++)
    {
        if(d[i]-d[i-1]>dis_max)
        {
            cout<<"No Solution";
            return 0;
            break;
        }
    }

    int j=0;
    //d1是总路程,d0就是移动的距离,如果d1-d0=0,
    //那么就意味着旅行家到达终点
    while(d1-d0)
    {
        for(int i=j+1;d[i]-d0<=dis_max && i<=n;i++)
        {
            if(pp[i]<pri_min)
            {
                pri_min = pp[i];
                j = i;
            }
        }
        //范围内的加油站比自己还便宜,那就
        //使加的油刚好能支持到达这个加油站
        if(pri_min<=p)
        {
            sum += ((d[j]-d0)/d2-l)*p;
            l = (d[j]-d0)/d2;
        }
        //这种情况指的是范围内的加油站都比自己贵,并且无法一次
        //到达终点,所以应该在自己这个最便宜的加油站直接加满
        else if(d1-d0>dis_max)
        {
            sum += (c-l)*p;
            l = c;
        }
        //这种情况 指的是范围内的加油站都比自己贵,但能一次
        //到达终点,那我肯定不管后面加油站了,直接奔向终点
        else
        {
            sum += ((d1-d0)/d2-l)*p;
            break;
        }
        //走多少里程,就相应地减去多少油
        l -= (d[j]-d0)/d2;
        //更新d0,表示旅行家的移动
        d0 = d[j];
        //更新p,方便下次进行比较
        p = pri_min;
        //还原pmin,以便下次搜索最小值
        pri_min = 505;
    }
    printf("%.2lf",sum);
    return 0;
}
  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小天才才

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值