pat1033To Fill or Not to Fill (25)

56 篇文章 0 订阅

题意分析:

(1)给出从出发地到目的地之间的若干个加油站的信息(每升价格 距出发点距离)以及油箱容量、目的地、每升油公里、油站数,出发时油箱为空,问要到达目的地的最少开销,如不能到达目的地,求出最多能够走多远。

这题分明显是一道贪心算法题,贪心算法题最主要的是理清贪心的策略:

算法前准备:

①将站点信息包装成结构体

②输入的站点时候过滤掉在目的地之外的站点(距离超过目的地),这些站点毫无用处,对后面的算法造成干扰

③对站点按照离出发点的距离升序排序

④将目的地看成是价格为0的加油站,这样处理起来比较统一

贪心策略:

①若车子当前在A站停留,若在A站加满油之后行驶却没有可达的任意站点,这时候最大距离为A.distance+maxDistance,maxDistance为加满油能行驶的最大距离

②若非①,设A站之后按顺序可达的站点有B、C、D....,在这些站中找出第一个价格比A站便宜的站点,然后在A站加到恰好能够到达此站的油量

③若非②,A之后可达站没有比A便宜的站点,且终点站包含在其中,则加油到恰好能够到达终点站

④若非③,在B、C、D....这些站中找出价格最便宜的站作为下一站,此时加满油行驶至该站,因为后面的站没有比当前更便宜的


可能坑点:

(1)当没有距离为0的站点时,永远不可达,最大距离永远是0.00

(2)邮箱油量(最大容量)、距离、每升油行驶公里数都是浮点数类型,且每到一个站加油时,要更新油箱中的油量才能计算出需要加多少油

(3)终点站一定没有剩余的油

(4)在贪心的后三步中无需考虑剩余的油是否可以支撑到下一个约定的加油站,理由很简单,如果剩余的油能够直接到达下一站,则此站无需停留。

(5)此题的测试数据不够严谨,在贪心策略的第三步,若加满油开到终点居然也可以通过测试

#include <iostream>
#include <algorithm>
#include <iomanip>
using namespace std;

struct station
{
    double price;
    double distance;
};
station s[501];
bool cmp(station a,station b)
{
    return a.distance<b.distance;
}
int main()
{
    double C,D,A;
    int N;
    cin>>C>>D>>A>>N;
    double maxDistance=C*A;
    int i=0;
    station temp;
    while(i<N)
    {
        cin>>temp.price>>temp.distance;
        //过滤掉目的地之外的加油站
        if(temp.distance<=D)s[i]=temp;
        i++;
    }
    s[i].price=0;
    s[i].distance=D;
    sort(&s[0],&s[i+1],cmp);
    if(s[0].distance!=0)
    {
        cout<<"The maximum travel distance = 0.00"<<endl;
        return 0;
    }
    double totalPrice=0;
    double maxLength=0;
    double remain=0;
    int j=0;
    while(j<i&&maxLength<D)
    {
        if((j<i-1)&&(s[j+1].distance-s[j].distance>maxDistance))
        {
            maxLength=s[j].distance+maxDistance;
            double cost=(C-remain)*s[j].price;
            totalPrice+=cost;
            break;
        }
        if(j==(i-1))
        {
            if(D-s[j].distance>maxDistance)
            {
                double cost=(C-remain)*s[j].price;
                totalPrice+=cost;
                maxLength=s[j].distance+maxDistance;
            }
            else
            {
                double cost=((D-s[j].distance-remain*A)/A)*s[j].price;
                totalPrice+=cost;
                maxLength=D;
            }
            break;
        }
        double minPrice=s[j+1].price;
        int nextStation=j;
        int cheapestStation=j+1;
        int flag=1;
        //确定下一个需要加油的站点
        for(int k=j+1;s[k].distance-s[j].distance<=maxDistance&&k<i;k++)
        {
            if(s[k].price<minPrice)
            {
                minPrice=s[k].price;
                cheapestStation=k;
            }
            if(flag&&s[k].price<=s[j].price)
            {
                nextStation=k;
                flag=0;
            }
        }
        if(minPrice>s[j].price)nextStation=cheapestStation;
        //如果下一确定要加油的站油费比当前站的油费要便宜或者相等,要加到恰好能够到达那一站
        //反之,如果下一确定要加油的站A比当前站的油费要贵,就干脆全加满,因为A站之后的站更不会比当前站更便宜了
        if(s[nextStation].price<=s[j].price)
        {
            //注意这里并不需要做判断,在此站加油,意味着油箱里的油不够到达下一站,反之如果能够到达下一站,何必要在此战停留呢
            double cost=((s[nextStation].distance-s[j].distance-remain*A)/A)*s[j].price;
            totalPrice+=cost;
            remain=0;
            maxLength=s[nextStation].distance;
        }
        else
        {
            if(D-s[j].distance>maxDistance)
            {
                double cost=(C-remain)*s[j].price;
                totalPrice+=cost;
                remain=C-(s[nextStation].distance-s[j].distance)/A;
                maxLength=s[nextStation].distance;
            }
            else
            {
                double cost=((D-s[j].distance-remain*A)/A)*s[j].price;
                totalPrice+=cost;
                remain=0;
                maxLength=D;
                break;
            }
        }
        j=nextStation;
    }
    if(maxLength==D)cout<<setiosflags(ios::fixed)<<setprecision(2)<<totalPrice<<endl;
    else cout<<"The maximum travel distance = "<<setiosflags(ios::fixed)<<setprecision(2)<<maxLength<<endl;
    return 0;
}

本题的坑点参考自Sup_Heaven的博客: http://blog.csdn.net/sup_heaven/article/details/19006527



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值