传送门
题目描述
一个旅行家想驾驶汽车以最少的费用从一个城市到另一个城市(假设出发时油箱是空的)。给定两个城市之间的距离 D1D1 、汽车油箱的容量 CC (以升为单位)、每升汽油能行驶的距离 D2D2 、出发点每升汽油价格 PP 和沿途油站数 NN ( NN 可以为零),油站 ii 离出发点的距离 DiDi 、每升汽油价格 PiPi ( i=1,2,…,Ni=1,2,…,N )。计算结果四舍五入至小数点后两位。如果无法到达目的地,则输出“No Solution”。
分析
本题即可贪心也可分治,以下为贪心的思路。
1.无解:若存在满油情况下,到不了下一个站,则无解
2.到了站p后,在可满油可到的范围内找费用最小的加油站k,若k的费用比p小,则将油量加到恰好到达k,否则在p处将油加满,到达k站
3.可用单调队列实现:假设到每个站都将油加满,并记录到该站时最多能加多少油(费用也先算上,到后面再减去),用单调队列选择费用最小的
对于从p->p + 1,期间的需要的油由前面若干个便宜的加油站提供。
将p站的加油费用加入单调队列(对于队列末端费用比它大的,踢出队列,顺便减去多加的费用)
注意到达终点是将单调队列清空,并减去其中多加的费用
代码
#include <cstdio>
#include <cstdlib>
#include <deque>
#define IL inline
#define open(s) freopen(s".in", "r", stdin); freopen(s".out", "w", stdout);
#define close fclose(stdin); fclose(stdout);
using namespace std;
IL int read()
{
int sum = 0;
int k = 1;
char c = getchar();
for(;'0' > c || c > '9'; c = getchar())
if(c == '-') k = -1;
for(;'0' <= c && c <= '9'; c = getchar())
sum = sum * 10 + c - '0';
return sum * k;
}
const int maxn = 10000 + 1;
struct node
{
double c;
double p;
IL node(double c_ = 0, double p_ = 0)
{
c = c_; p = p_;
}
};
int n;
double cap, cd;
double ans;
deque<node> Q;
double dis[maxn], price[maxn];
int main()
{
open("traveller")
scanf("%lf %lf %lf %lf", &dis[0], &cap, &cd, &price[0]); n = read() + 1;
dis[n] = dis[0]; dis[0] = 0;
for(int i = 1; i <= n; ++i)
{
if(i < n) scanf("%lf %lf", &dis[i], &price[i]);
if(dis[i] - dis[i - 1] > cap * cd) { ans = -1; break;}
}
if(!ans)
{
double c1 = cap, c;
ans += price[0] * cap;
Q.push_back(node(cap , price[0]));
for(int i = 1; i <= n; ++i)
{
c = (dis[i] - dis[i - 1]) / cd;
c1 -= c;
for(;!Q.empty() && c;)
{
if(Q.front().c > c)
{
Q.front().c -= c;
break;
}else
{
c -= Q.front().c;
Q.pop_front();
}
}
if(i == n)
{
for(;!Q.empty(); Q.pop_back()) ans -= Q.back().p * Q.back().c;
break;
}
for(;!Q.empty() && Q.back().p >= price[i];)
{
ans -= Q.back().p * Q.back().c;
c1 -= Q.back().c;
Q.pop_back();
}
ans += price[i] * (cap - c1);
Q.push_back(node(cap - c1, price[i]));
c1 = cap;
}
}
if(ans == -1) printf("No Solution\n"); else printf("%.2lf\n", ans);
close
return 0;
}