PAT-AL 1033. To Fill or Not to Fill

1、知识点:贪心
2、思路:先将站按照距离从小到大排序。假设我有N个桶,第i号桶装第i站的汽油(i从0开始),第0站加满,到第i站时,选择从第i-1站到达此站最便宜的汽油(如果最便宜的不够用,选择次便宜的),然后将N个桶中所有比此站更贵的汽油原价卖出(说明之前买的多了,够用就好),然后加此站的油至加满(不管是不是比之前或后面的更贵,因为不加满怕到不了下个站)。最后到达终点时将所有剩下的油原价卖出即可。

3、注意:①如果第0号站的初始距离不是0,说明最大距离就是0;
②对于第i站,还要判断能否从第i-1站到达此站;
③有的站距离可能超过终点。

/*用途:
**说明:
**算法:
*/

//#define LOCAL
#include <cstdio>
#include <algorithm>
using namespace std;
#define MAXPRICE 2147483647   //最大油价
#define MAXN 500+10
struct station{
    double price;   //油价
    double dis;     //距离原点
};

struct mybox{       //桶结构
    double price;   //油价
    double vol;     //油量
};
double Cmax, D, Davg;
int N;
station sta[MAXN];
vector<mybox> box;  //桶向量
double money;       //最终花费

bool cmp_dis(station a, station b);   //按距离从小到大排序
bool can_arrive(int n);   //判断能否到达第n站
double get_far(int n);    //最终能走多远
void clear_and_plus(int n);   //用掉便宜油,加上此站油
void add_box(mybox mb);   //每到一个站,添加一个桶
void update(int n, double &plu);  //维护桶
void repay();   //卖出剩下的油
int main()
{
#ifdef LOCAL
    freopen(".in", "r", stdin);
    freopen(".out", "w", stdout);
#endif

    scanf("%lf%lf%lf%d", &Cmax, &D, &Davg, &N);
    for(int i=0; i<N; i++)
        scanf("%lf%lf", &(sta[i].price), &(sta[i].dis));

    sort(sta, sta+N, cmp_dis);
    if(sta[0].dis){   //如果0号站距离不为0
        printf("The maximum travel distance = 0.00");
            return 0;
    }

    sta[N].price = MAXPRICE;   //假设终点站的油天价
    sta[N].dis = D;

    mybox mb;    //起点站对应的桶
    mb.price = sta[0].price;   
    mb.vol = Cmax;
    box.push_back(mb); 
    money += mb.price * Cmax;   

    for(int i=1; i<N+1; i++){
        if(!can_arrive(i)){   //如果不能到达此站
            printf("The maximum travel distance = %.2lf", get_far(i));
            return 0;
        }
        else if(sta[i].dis >= D){   //此站已超过或就是终点
            clear_and_plus(i);
            repay();
            printf("%.2lf", money);
            return 0;
        }
        clear_and_plus(i);
    }

    return 0;
}

bool cmp_dis(station a, station b)
{
    return a.dis < b.dis;
}

bool can_arrive(int n)
{
    return Cmax * Davg >= sta[n].dis - sta[n-1].dis;
}

double get_far(int n)
{
    return sta[n-1].dis + Davg*Cmax;
}

void clear_and_plus(int n)
{
    double need, plus;   //从第n-1站到第n站所需油
    plus = need = (sta[n].dis - sta[n-1].dis) / Davg;
    int len = box.size();
    for(int i=0; i<len && need>0; i++){   //桶已经按照油价升序排列
        if(box.at(i).vol >= need){   //该桶油够用
            box.at(i).vol -= need;
            break;
        }
        else{   //该桶油不够用
            need -= box.at(i).vol;
            box.at(i).vol = 0;
        }
    }   
    update(n, plus);   //维护桶向量(注意:plus引用传递)

    mybox mb;
    mb.price = sta[n].price;
    mb.vol = plus;
    add_box(mb);        //加桶
    money += sta[n].price * plus;   //加上此站油钱
}

void add_box(mybox mb)
{
    int len = box.size();
    for(int i=0; i<len; i++){
        if(mb.price < box.at(i).price){   //将新添加的桶按照价格升序插入
            box.insert(box.begin()+i, mb);
            return;
        }
    }
    box.push_back(mb);
}

void update(int n, double &plu)
{
    for(int i=0; i<box.size(); i++)
        if(box.at(i).vol == 0 || box.at(i).price > sta[n].price){   //如果是空桶或者该桶油价比第n站贵,原价卖掉
            plu += box.at(i).vol;
            money -= box.at(i).price * box.at(i).vol;
            box.erase(box.begin() + i);
            i--;
        }
}

void repay()
{
    int len = box.size();
    for(int i=0; i<len; i++)
        money -= box.at(i).price * box.at(i).vol;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值