洛谷P1016 旅行家的预算 题解 贪心+单调队列

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

解题思路(思路全部来自 hongzy大神的博客):

思路:

  1. 在起点加满油;
  2. 到第i个加油站把油箱里价格>P[i]的油退了,换成价格为P[i]的油。
  3. 每次烧油就找最便宜的油烧

实现:单调队列,每次取front的烧油,再把当前的油用单调队列方式插入队尾.

单调队列的插入方式:back 比当前 P[i] 大 就 pop 直到 back <= P[i] 再插入

实现代码如下:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 550;
double D1, C, D2, P;
int n;
struct OilStation {
    double d, p;
} os[maxn];
bool cmp(OilStation a, OilStation b) {
    return a.d < b.d;
}
deque<pair<double, double> > que; // <体积,单价>
double cost;
int main() {
    scanf("%lf%lf%lf%lf%d", &D1, &C, &D2, &P, &n);
    for (int i = 1; i <= n; i ++) scanf("%lf%lf", &os[i].d, &os[i].p);
    sort(os+1, os+n+1, cmp);
    os[0].d = 0;
    os[0].p = P;
    while (os[n].d >= D1) n --;
    n ++;
    os[n].d = D1;
    os[n].p = 0;
    que.push_back(make_pair(C, P));
    for (int i = 1; i <= n; i ++) {
        double c = (os[i].d - os[i-1].d) / D2;
        while (!que.empty()) {
            pair<double, double> pp = que.front();
            que.pop_front();
            if (pp.first < c) {
                c -= pp.first;
                cost += pp.first * pp.second;
            }
            else {
                pp.first -= c;
                cost += c * pp.second;
                que.push_front(pp);
                break;
            }
        }
        if (que.empty() && c > 0) {
            puts("No Solution");
            return 0;
        }
        c = (os[i].d - os[i-1].d) / D2;
        while (!que.empty() && que.back().second > os[i].p) {
            c += que.back().first;
            que.pop_back();
        }
        que.push_back(make_pair(c, os[i].p));
    }
    printf("%.2lf\n", cost);
    return 0;
}
posted @ 2020-02-18 12:04  quanjun  阅读(182)  评论(0编辑  收藏  举报