【PAT 1033】To Fill or Not to Fill

0 篇文章 0 订阅

题目地址:http://www.patest.cn/contests/pat-a-practise/1033

所用算法:贪心算法

分析:

1. 既然油箱初始为空,那么想要最便宜的方案,到终点的时候,油箱也必须为空。

2. 每个地点的加油策略:

设当前所在位置为 A,则开始寻找下一个加油位置,设为 B,将输入的加油站的位置按照距离的远近进行排序,每次遍历一个加油站。一次性跑的最远的距离为 maxPerTank = Cmax * Davg。

(1) 如果两个相邻的加油站之间的距离大于 maxPerTank,则无法到达终点,本次 case 结束。

(2) 若 B 点的油价低于 A 点,则需要油箱中的油量为可以恰好从 A 点跑到 B 点所需要的油量。

(3) 若 B 点的油价高于 A 点且两点之间的距离小于 maxPerTank,则查看下一个加油站。

(4) 若 B 点的油价高于 A 点但两点之间的距离大于 maxPerTank,则在 A 点加满油,并将 A 和 B 之间油价最便宜的加油站 C 为目的地,到达 C 以后,继续按照从 (2) - (4) 的步骤判断。

源代码(但在 PAT 中有一个测试用例无法通过,希望朋友们看出来代码的问题给我留言):

#include <iostream>
#include <vector>
#include <algorithm>
#include <iomanip>

using namespace std;

struct Station {
    float P;
    float Dis;
    
    bool operator < (const Station &a) const {
        return Dis < a.Dis;
    }
};

short getMin(vector<Station> st, short begin, short end);

int main() {
    
    cout.setf(ios::fixed);
    short Cmax = 0, D = 0, Davg = 0, N = 0;
    while (cin >> Cmax >> D >> Davg >> N) {
        short maxPerTank = Cmax * Davg;
        vector<Station> st(N);
        
        // Accept Input
        for (short i = 0; i < N; ++i) {
            cin >> st[i].P >> st[i].Dis;
        }
        
        // 将目的地加入结点
        Station des;
        des.P = 0.0;
        des.Dis = D;
        st.push_back(des);
        
        sort(st.begin(), st.end());
        
        // 无法到达
        float farthest = 0;
        bool isReachable = true;
        for (short i = 0; i < N; ++i) {
            if (st[i].Dis + maxPerTank < st[i + 1].Dis) {
                isReachable = false;
                farthest = st[i].Dis + maxPerTank;
                break;
            }
        }
        if (!isReachable) {
            cout << "The maximum travel distance = " << setprecision(2) << farthest << endl;
            continue;
        }
        
        // 可以到达,计算最便宜的方案
        float sum = 0.0;
        float needGas = 0.0;
        float nowPos = 0.0;
        short i = 1, last = 0;
        float priceLast = st[0].P;
        float gasLeft = 0.0;
        
        while (i < N + 1) {
            if (st[i].Dis - nowPos <= maxPerTank) {
                if (st[i].P < priceLast) {
                    needGas = (st[i].Dis - nowPos) / Davg;
                    if (gasLeft >= needGas) {
                        gasLeft -= needGas;
                        nowPos = st[i].Dis;
                        priceLast = st[i].P;
                        last = i;
                        ++i;
                    } else {
                        sum += (needGas - gasLeft) * priceLast;
                        gasLeft = 0.0;
                        nowPos = st[i].Dis;
                        priceLast = st[i].P;
                        last = i;
                        ++i;
                    }
                } else {
                    ++i;
                }
            } else {
                short minPos = getMin(st, last + 1, i - 1);
                sum += (Cmax - gasLeft) * priceLast;
                gasLeft = Cmax - (st[minPos].Dis - nowPos) / Davg;
                nowPos = st[minPos].Dis;
                priceLast = st[minPos].P;
                last = minPos;
                i = minPos + 1;
            }
        }
        
        cout << setprecision(2) << sum << endl;
    }
    
    return 0;
}

short getMin(vector<Station> st, short begin, short end) {
    short ret = begin;
    
    for (short i = begin; i <= end; ++i) {
        if (st[i].P < st[ret].P) {
            ret = i;
        }
    }
    
    return ret;
}



希望朋友们多多指教!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值