PAT_1033 To Fill or Not to Fill(贪心)

题目链接
一开始大体贪心的思想是差不多的,在当前能覆盖的范围内找价格最便宜的加油站,根据情况选择从当前加油站加满还是到下一个加油站进行加油。

但是这并不完全正确,应该是从当前位置能覆盖到的范围内先找是否有比当前加油站a还便宜的加油站b,如果有则从a恰好运动到这种加油站b,否则找一个覆盖范围内最便宜的加油站c,然后从a加满油运动到c,再进行迭代判断。

因为加满的情况到加油站c还会剩余油,这样在选择去下一个加油站的时候需要加的油就要考虑到剩余的油量(即要减去这部分)。
在这里插入图片描述
这里作差为负的情况是不存在的,因为假设为负,首先说明curC不为零,即说明上一站q是加满了油,找覆盖到的最便宜的加油站才到本站x并剩下油,然后以x为基点搜出比x还便宜的站c,如果作差这里为负,说明从q本身就能覆盖到这个更小的站c,而不必经过当前正在处理的加油站x,即q到的下一站本该就是c而不是x。

此题比较巧妙的是把终点视作价格为0距离起点为D的加油站,这样如果在能到达的覆盖范围,因为价格为0是最小的,所以肯定会被算法选择到;如果覆盖范围不包括终点,也就意味着寻找不到上述加油站b或c,则就输出最远能到的距离。

完整代码:

#include <iostream>
#include <bits/stdc++.h>
using namespace std;
struct Station{
    double price;
    double dis;
    Station(double _price,double _dis){
        price=_price;
        dis=_dis;
    }
    Station(){}
}stations[505];
bool cmp(Station a,Station b){
    return a.dis<b.dis;
}
int main() {
#ifdef ONLINE_JUDGE
#else
    freopen("1.txt","r",stdin);
#endif
    double Cmax,D,Davg;
    int N;
    cin >> Cmax >> D >> Davg >> N;
    for(int i=0;i<N;i++){
        double price,dis;
        cin >> price >> dis;
        stations[i]=Station(price,dis);
    }
    //将目的地视为price为0的加油站
    stations[N]=Station(0,D);
    sort(stations,stations+N+1,cmp);
    double resCost=0;//记录最终的花费
    bool flag=true;//能到达终点
    double curDis;
    if(stations[0].dis!=0){
        cout << "The maximum travel distance = 0.00";
    }else{
        int curPos=0;//当前所在加油站与当前油箱剩余油
        double curC=0;//!!!!!!!!!!!一开始把剩余油量设置为int了,需要是double,因为剩余未必整数
        while(curPos<N){//未到达终点就一直循环
            curDis=stations[curPos].dis;//当前距离起点的位置
            int m=-1,M=-1;//m记录遇到的比当前小的,M记录遇到的最小的
            for(int i=curPos+1;i<=N;i++){//!!!!!!!i能取到N,因为要能到终点啊
                if(stations[i].dis > curDis+Cmax*Davg){
                    break;//超过能覆盖的范围就终止
                }
                if(stations[i].price<stations[curPos].price){
                    m=i;
                    break;
                }else if(M==-1 || stations[i].price < stations[M].price){
                    M=i;
                }
            }
            if(m==-1 && M==-1){
                flag=false;
                break;
            }
            if(m!=-1){//遇到比当前价格小的加油站,加到恰好到这个加油站
                resCost+=((stations[m].dis-stations[curPos].dis)/Davg-curC)*stations[curPos].price;
                curPos=m;
                curC=0;
            }else{//没遇到比当前小的加油站,则加满油跑到这部分的价格最小的加油站
            //因为目的地的价格是0,所以肯定会比当前小的,即这种情况肯定不会经过终点
            resCost+=(Cmax-curC)*stations[curPos].price;
            curC=Cmax-(stations[M].dis-stations[curPos].dis)/Davg;
            curPos=M;
            }
        }
        if(flag)
            printf("%.2f",resCost);
        else printf("The maximum travel distance = %.2f",double(curDis+Cmax*Davg));
    }

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值