[PAT解题报告] To Fill or Not to Fill

经典问题,汽车加油问题,从起点到终点,有若干个加油站,每个加油站油价不同,汽车油箱容积有限,问能否到终点,如何最便宜。

可以贪心, 我比较喜欢的做法。到当前加油站,就把油箱加满。 我们把油箱里的油看成是“分块”的,每块油有自己的价钱。我们使用油的时候从最便宜的开始用。加油的时候,如果当前加油站的油比邮箱里的还没用的油便宜,就把贵的油换掉。
所以油箱里的油可以存储为这样的pair, (价钱,油量) ,到达一个加油站,就把所有油价比它贵的油用这个加油站的油换掉,所以离开加油站的时候,油箱总是满的,使用的时候先用最便宜的油。注意:最后没有使用的油是不算钱的,可以理解为我们把油退回去。所以只有真正使用的油,才算钱,加油时,并不算钱。
那么这个油箱其实可以使用一个队列存所有的pair。 这个队列自然单调的,比如,我们可以维从队头到队尾的油逐渐变贵。那么我们使用的时候,从队头的油开始用,加油的时候,看一下如果队尾的油比当前加油站贵,就从队尾把油弹出来,不断弹出来,最后再用当前加油站的油加满。所以当前加油站的油比邮箱里存下的油贵,但是对于要换掉的油,它是便宜的,我们用便宜的油换了贵的油。

所以时间复杂度是O(n)的……
另外一点你要注意的是,浮点数比较大小最好使用eps,这点比较讨厌。

代码:
#include <cstdio>
#include <cstring>
#include <deque>
#include <algorithm>

using namespace std;

const double eps = 1.e-8;
pair<double, double> g[505];

deque<pair<double,double> >  q;

int main() {
int n;
double tank, dis, avg;

    scanf("%lf%lf%lf%d",&tank, &dis, &avg, &n);
    for (int i = 0; i < n; ++i) {
        scanf("%lf%lf",&g[i].second, &g[i].first);
    }
    g[n++] = make_pair(dis, 0.);
    sort(g, g + n);
    double cost = 0., now = 0., oil = 0.;
    for (int i = 0; (i < n) && (now + eps <= dis); ++i) {
        double d = g[i].first - now;
        while ((!q.empty()) && (d >= eps)) {
            double need = d / avg;
            if (q.front().second < need + eps) {
                double temp = q.front().second * avg;
                now += temp;
                cost += q.front().second * q.front().first;
                oil -= q.front().second;
                d -= temp;
                q.pop_front();
            }
            else {
                now += d;
                cost += need * q.front().first;
                q.front().second -= need;
                oil -= need;
                d = 0.;
            }
        }
        if (d >= eps) {
            break;
        }
        while ((!q.empty()) && (q.back().first >= g[i].second + eps)) {
            oil -= q.back().second;
            q.pop_back();
        }
        if (oil + eps <= tank) {
            q.push_back(make_pair(g[i].second, tank - oil));
            oil = tank;
        }
    }
    if (now + eps > dis) {    
        printf("%.2lf\n",cost);
    }
    else {
        printf("The maximum travel distance = %.2lf\n",now);
    }
    return 0;
}

原题链接: http://www.patest.cn/contests/pat-a-practise/1033


全部评论
可能是我智商太低了,读你的代码真的好累,一些细节的处理不加注释
3 回复 分享
发布于 2019-08-09 00:58
思路很好,讲的也很清楚,相当于车主可以选择使用油以及卖掉油,在后面的站点可以卖前面站点的油,但是只能买这个站点的油.
点赞 回复 分享
发布于 2017-02-17 19:19
思路真的很创新,但是作为一个普通人只能这样赞叹了吧,反正我考场上是不可能想到这种做法的
点赞 回复 分享
发布于 2019-08-09 01:08
brilliant!
点赞 回复 分享
发布于 2018-09-04 17:10

相关推荐

11-11 14:21
西京学院 C++
无敌混子大王:首先一点,不管学校层次怎么样,教育经历放在第一页靠上位置,第一页看不到教育经历,hr基本直接扔掉了
点赞 评论 收藏
分享
11-15 19:28
已编辑
蚌埠坦克学院 硬件开发
点赞 评论 收藏
分享
6 4 评论
分享
牛客网
牛客企业服务