代码改变世界

PAT 1033. To Fill or Not to Fill (25)

2014-05-07 10:55  微尘_无名  阅读(180)  评论(0编辑  收藏  举报

题目地址:http://pat.zju.edu.cn/contests/pat-a-practise/1033

此题是一道贪心算法题,难度较大,关键在于贪心策略的选择:

#include <cstdio>
#include <vector>
#include <algorithm>
#include <climits>
using namespace std;

struct GasStation
{
    double price;
    double distance;
    bool operator<(const GasStation& rhs) const
    {
        return distance<rhs.distance;
    }
};

vector<GasStation> gasStations;
int _tmain(int argc, _TCHAR* argv[])
{
    double Cmax,D,Davg;
    int N;
    scanf("%lf %lf %lf %d",&Cmax,&D,&Davg,&N);
    GasStation station;
    int i;
    for(i=0;i<N;++i)
    {
        scanf("%lf %lf",&station.price,&station.distance);
        gasStations.push_back(station);
    }
    //将目的地当做最后一个加油站,距离为D,价格为0,以便贪心选择时总是朝着目的地前进
    station.distance=D;  
    station.price=0;
    gasStations.push_back(station);
    sort(gasStations.begin(),gasStations.end());
    if(gasStations[0].distance>0)
    {
        printf("The maximum travel distance = 0.00\n");
        return 0;
    }
    double curGas=0.0,minSpend=0.0,minPrice;
    const double driveLimit=Cmax*Davg;
    int j,pivot;
    for(i=0;i<N;) //在前N个加油站都有可能加油
    {
        if(gasStations[i+1].distance-gasStations[i].distance>driveLimit)
        {
            printf("The maximum travel distance = %.2lf\n",gasStations[i].distance+driveLimit);
            return 0;
        }
        pivot=i;
        minPrice=gasStations[i].price;
        //如果有油,找到不加油就能开到的比当前加油站便宜的加油站,直接开到那里加油
        double curDis=curGas*Davg;
        for(j = i+1;j<=N && gasStations[j].distance-gasStations[i].distance <= curDis;++j)
        {
            if(gasStations[j].price<minPrice)
            {
                minPrice=gasStations[j].price;
                pivot=j;
            }
        }
        if(pivot!=i)
        {
            curGas-=(gasStations[pivot].distance-gasStations[i].distance)/Davg;
            i=pivot;
            continue;
        }

        //以当前邮箱里面的油能跑到的范围内没有比当前加油站更便宜的加油站,于是在当前加油站后跑到第一个比当前
        //加油站便宜的加油站
        for(j=i+1;j<=N && gasStations[j].distance-gasStations[i].distance <= driveLimit;++j)
        {
            if(gasStations[j].price<minPrice)
            {
                pivot=j;
                break;
            }
        }
        if(pivot!=i)
        {
            minSpend+=((gasStations[pivot].distance-gasStations[i].distance)/Davg-curGas)*gasStations[i].price;
            i=pivot;
            curGas=0;
            continue;
        }

        //就算加满油后也不能跑到一个比当前加油站更便宜的加油站,则在加满油后跑到能跑到的加油站里面最便宜的一个
        minPrice=INT_MAX;
        for(j=i+1;j<=N && gasStations[j].distance-gasStations[i].distance<=driveLimit;++j)
        {
            if(gasStations[j].price<minPrice)
            {
                minPrice=gasStations[j].price;
                pivot=j;
            }
        }
        minSpend+=(Cmax-curGas)*gasStations[i].price;
        curGas=Cmax-(gasStations[pivot].distance-gasStations[i].distance)/Davg;
        i=pivot;
    }
    printf("%.2lf\n",minSpend);

    return 0;
}
View Code