题目 A1033 To Fill or Not to Fill
-
题意
输入汽车油箱容量,需要行驶的距离,单位油量行驶的距离以及加油站个数n
。然后随后输出n
个加油站的信息,油价及据起点的距离。输出若能达到目的地的最小开销,若不能达到,输出最大行驶距离。 -
思路
这题其实贪心的目标就是,花最少的钱。所以每次加油的时候应该尽量考虑如何使得我买到的油是最便宜的。代入场景中其实需要思考的点就是:① 我需要在这个加油站加多少油的问题 ② 我下一个要达到的加油站是哪个。很明显,我们是想要到最便宜的加油站加油的,而且是我们能到达范围内(满载行驶距离内)最便宜的,这个可以解决问题②。如果当前的加油站价格比下一个加油站的要贵的话,那我们只需要加到能到下一个加油站的油量就可以了。如果当前的价格最便宜,那当然是加满最划算。这就是解决问题①的思路。
最后验证一下合理性,假设三个加油站a,b,c。若油价a>b,则当然是去b加剩下的油比在a处加要划算。同理若a<b<c,则在a处加满再去b,c中油价低的较为划算。 -
Code in C++
#include <cstdio>
#include <limits>
#include <algorithm>
#define maxn 510
struct station {
double price;
double distance;
} st[maxn];
bool cmp(const station &a, const station &b) {
return a.distance < b.distance;
}
int main()
{
double c, d, d_a;
int n;
scanf("%lf %lf %lf %d", &c, &d, &d_a, &n);
for (int i = 0; i < n; ++i)
{
scanf("%lf %lf", &st[i].price, &st[i].distance);
}
// 将终点加入加油站中
st[n].price = 0.0;
st[n].distance = d;
// 按距离对加油站进行排序
std::sort(st, st + n, cmp);
// 判断起点处是否有加油站
if (st[0].distance != 0)
{
printf("The maximum travel distance = 0.00");
}
else
{
int now = 0; // 当前所在加油站编号
double curTank = 0, sum = 0, maxDistance = c * d_a;
while (now < n)
{
// 在满载能行进的范围内找最低价的加油站进行加油
int k = -1;
double price_min = std::numeric_limits<double>::max();
for (int i = now + 1; i <= n && st[i].distance - st[now].distance <= maxDistance; ++i) {
if (st[i].price < price_min)
{
price_min = st[i].price;
k = i;
if (price_min < st[now].price) break;
}
}
// 判断是否没有能够行使到的加油站
if (k == -1) break;
// 有能行使到的加油站
double tank = (st[k].distance - st[now].distance) / d_a;
if (price_min < st[now].price)
{
if (curTank < tank)
{
sum += (tank - curTank) * st[now].price;
curTank = tank;
}
}
else
{
sum += (c - curTank) * st[now].price;
curTank = c;
}
now = k;
curTank -= tank;
}
if (now == n)
{
printf("%.2f", sum);
}
else
{
printf("The maximum travel distance = %.2f", st[now].distance + maxDistance);
}
}
return 0;
}
小结
感觉自己对于贪心好像理论还是掌握的不是很足,这题能想到要去尽可能低的油价的加油站去加油(代入现实生活场景),但是具体代码上的逻辑没想到是在最大行驶范围内找最低价,然后还是找到第一个最低价的加油站就过去,我看到解析里面都还进行了贪心理论证明,看来需要理论结合实际来刷题了。