没看题解之前想用动态规划去解这道题,毫无疑问GG了
参考了一位博主的思路和代码
到当前加油站,就把油箱加满。 我们把油箱里的油看成是“分块”的,每块油有自己的价钱。我们使用油的时候从最便宜的开始用。加油的时候,如果当前加油站的油比邮箱里的还没用的油便宜,就把贵的油换掉。所以离开加油站的时候,油箱总是满的,使用的时候先用最便宜的油。注意:最后没有使用的油是不算钱的,可以理解为我们把油退回去。所以只有真正使用的油,才算钱,加油时,并不算钱。
去维护一个双向队列,队列里存放的是pair<油价,油的数量>.
每当到一个站点,把当前站点的油价和队列里的back()元素的油价开始对比,把队列里油价>当前站点油价的pair不断地pop_back().最后剩下的在队列里的油一定是比当前站点的便宜的.这样之后就相当于把邮箱里没用掉的价格昂贵的油还给之前的加油站了.
如果导致了我们油箱没满,则用当前站点的形成新的pair<油价,油箱置换掉贵的油之后剩下的空间>加入到队列中(只是先放到油箱中,不一定会用到)
这样队列里面的油价从front()到back()是依次增大的.
我们在去下一个站点前,计算出与下一个站点的距离和油耗需求量.
然后从队列的front()开始耗油,每当一个队头pair油量耗尽,就pop_front().
直到油耗需求量被满足为止.
#include <iostream>
#include <deque>
#include <algorithm>
using namespace std;
double tank,destination,avg;
int N;
struct station
{
double price,dist;
}s[505];
struct Oil
{
double price,num;
Oil(double p,double n)
{
price=p;
num=n;
}
};
deque<Oil> q;
int cmp(station a,station b)
{
return a.dist<b.dist;
}
int main()
{
cin>>tank>>destination>>avg>>N;
for(int i=0;i<N;i++)
cin>>s[i].price>>s[i].dist;
s[N].dist=destination;
sort(s,s+N+1,cmp);
double nowcost=0,nowdist=0,nowoil=0;
for(int i=0;i<=N;i++)
{
//计算与下一个站点的距离
double distToNextStation=s[i].dist-nowdist;
while(!q.empty()&&distToNextStation>0&&i!=0)
{
double needOfOilNum=distToNextStation/avg;
//最便宜的那层油的数量 不能够满足 到下一站点油耗需求量
if(q.front().num<needOfOilNum)
{
nowoil-=q.front().num;
nowcost+=q.front().price*q.front().num;
nowdist+=q.front().num*avg;
distToNextStation-=q.front().num*avg;
q.pop_front();
}
//最便宜的那层油的数量 能够满足 到下一站点的油耗需求量
else
{
nowoil-=needOfOilNum;
nowcost+=needOfOilNum*q.front().price;
nowdist+=distToNextStation;
distToNextStation=0;
q.front().num-=needOfOilNum;
}
}
if(distToNextStation>0)
break;
//取出油箱里价格比当前站点油价昂贵的油
while(!q.empty()&&q.back().price>s[i].price)
{
nowoil-=q.back().num;
q.pop_back();
}
//放入当前站点的油
if(nowoil<tank)
{
q.push_back(Oil(s[i].price,tank-nowoil));
nowoil=tank;
}
}
if(nowdist<destination)
printf("The maximum travel distance = %.2lf\n",nowdist);
else
printf("%.2lf",nowcost);
}
|