洛谷P1016 旅行家的预算 题解 贪心+单调队列
题目链接:https://www.luogu.com.cn/problem/P1016
解题思路(思路全部来自 hongzy大神的博客):
思路:
- 在起点加满油;
- 到第i个加油站把油箱里价格>P[i]的油退了,换成价格为P[i]的油。
- 每次烧油就找最便宜的油烧
实现:单调队列,每次取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;
}