P1016 旅行家的预算【模拟+贪心】【详解】

题目链接

思路

  这道题是一道很明显的模拟题,但这道题也需要自己的理解,我自己写了些样例,然后找到了其中的模拟,我们假设从一个点出发,对于它的下一个点我们有很多选择,期间定义一个len用以记录满油(单次最远)到达距离,我们造访这条路上的所有点,如果存在“<=”目前节点油价的点,就走开到那个点,那么我们要加多少油?于是,我定义了now_oil记录到达目标点后剩余油量,每次询问该点往后的所有点,找到第一个("<=")即退出循环,然后抵达该点,now_oil就“=0”了,然而,假如这条路径上没有比它便宜的店了,那么这次就直接加满c,然后,访问下一个节点,看看从它出发是否存在更加便宜的店,找到便宜的,然后就抵达它,期间会需要耗油,但是与前面“<=”的情况会有不同,你会发现,这是有油时候达到的情况,那如何处理?我们可以还是抵达该点,然后处理:从目前点到该点需要need_oil的量的油,如果原本now_oil的油还够花,就说明到达该点的钱还是会贵些,但却是其他中最便宜的了,我们不增加花费的钱,我们减去目前剩的油即可,但是若是need_oil>now_oil,就说明得花点钱了,具体花多少,得看need_oil - now_oil的值了。

  细节

本题并没有说明加油站是按顺序排列的,需要注意!!!

无法抵达终点:两两路径中,存在某一路径长大于满油时的最远行驶路径。

 

完整代码:

//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
using namespace std;
typedef long long ll;
const int maxN=10;
double d1,c,d2,p;
int N;
struct node
{
    double pos,cost;        //距离初始点距离、该油站花费价格
    node(double a=0, double b=0):pos(a),cost(b) {}
}oil[maxN];
bool cmp(node e1, node e2)      //距离原点最近的在前
{
    return e1.pos<e2.pos;
}
int main()
{
    while(scanf("%lf%lf%lf%lf%d",&d1,&c,&d2,&p,&N)!=EOF)
    {
        double cost=0, len=c*d2, now_oil=0,det_l=0;     //总计花费、满油到达距离,目前石油量
        memset(oil, 0, sizeof(oil));
        N+=2;
        oil[1]=node(0, p);      oil[N]=node(d1, 0);
        for(int i=2; i<N; i++) scanf("%lf%lf",&oil[i].pos,&oil[i].cost);
        sort(oil+1, oil+1+N, cmp);
        for(int i=2; i<=N; i++) det_l=max(det_l, oil[i].pos-oil[i-1].pos);
        if(len<det_l)       //无法抵达终点
        {
            printf("No Solution\n");
            continue;
        }
        int k=1;
        while(k<=N)
        {
            int i;
            for(i=k+1; i<=N && oil[k].pos+len>=oil[i].pos; i++)
            {
                if(oil[i].cost<=oil[k].cost)        //找到比这个站台便宜的下个站台,若是找不到就直接加满
                {
                    double need_oil=(oil[i].pos-oil[k].pos)/d2;
                    if(now_oil<need_oil)
                    {
                        cost+=oil[k].cost*(need_oil-now_oil);
                        now_oil=0;
                    }
                    else now_oil-=need_oil;
                    k=i;
                    break;
                }
            }
            if(i!=k)        //没找到,直接加满,然后去寻找下个便宜的
            {
                cost+=(c-now_oil)*oil[k].cost;
                now_oil=c-(oil[k+1].pos-oil[k].pos)/d2;
                k++;
            }
        }
        printf("%.2lf\n", cost);
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Wuliwuliii

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

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

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

打赏作者

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

抵扣说明:

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

余额充值