ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Leetcode 871.最低加油次数(dp / 贪心+优先队列)

2022-07-02 19:35:34  阅读:156  来源: 互联网

标签:temp stations int long 871 加油站 startFuel Leetcode dp


  考虑可以用多种解法解决该题。

  首先很容易想到用$O(n^2)$的递推dp。设$d[i][j]$为到达第i站前加油次数为j时的最大油量,最后直接找终点最小值就行。鉴于数据规模比较小,stations.length<=500,因此$O(n^2)$是可以通过的。

long long d[503][503];

class Solution {
public:
    int minRefuelStops(int target, int startFuel, vector<vector<int>>& stations) {
        memset(d,-1,sizeof(d));
        int lim=stations.size();
        vector<int> temp;temp.push_back(target),temp.push_back(0);
        stations.push_back(temp);
        d[0][0]=startFuel-stations[0][0];
        if (d[0][0]<0)      //第0站都开不到
            return -1;
        
        for (int i=1;i<=lim;i++){
            d[i][0]=(long long)((d[i-1][0]-(stations[i][0]-stations[i-1][0]))>=0?d[i-1][0]-(stations[i][0]-stations[i-1][0]):-1);
            long long a,b;
            for (int j=1;j<=lim;j++){
                if (d[i-1][j]>=0)
                    a=(long long)(d[i-1][j]-(stations[i][0]-stations[i-1][0]));    //上一站不加
                else a=-1;
                if (d[i-1][j-1]>=0)
                     b=(long long)(d[i-1][j-1]+stations[i-1][1]-(stations[i][0]-stations[i-1][0]));  //上一站加
                else b=-1;
                if (a>=0||b>=0)
                    d[i][j]=a>b?a:b;
            }
        }   
        for (int i=0;i<=lim;i++)
            if (d[lim][i]>=0)
                return i;
        return -1;
    }
};
//d[i][j]到达第i个站之前加油次数为j次时剩余油量
//d[i+1][j]=max{d[i][j],d[i][j-1]+stations[i][1]}-(stations[i+1][0]-stations[i][0])

  

  打完后会发现这种解法的效率是比较低下的,考虑其他更优的解法。很容易想到或许可以用贪心:在某个点带着油出发后,我们先考虑一口气走到没油为止。如果能走到终点当然最好;如果走不到终点,在油耗尽的位置(设为位置A),我们再回头挑选来路的加油站,再看本应该在哪个加油站加。

  挑选来路的加油站时,假设有B、C、D三个加油站,且分别有b、c、d升的油,如下图:

  显然这时应当选择的最优加油站是油最多的那个。因为路已经走过了已经消耗过油了,我们从来路的加油站提取油是不用消耗路程的。因此只需要用一个堆(或者优先队列)维护来路上最多油的站。

  复杂度是$O(nlogn)$。

class Solution {
public:
    int minRefuelStops(int target, int startFuel, vector<vector<int>>& stations) {
        int cnt=0;
        priority_queue<int> que;
        int line=startFuel,lim=stations.size();
        for (int i=0;i<lim;i++)
            if (line>=stations[i][0])  //可以到
                que.push(stations[i][1]);
            else{      //不能到,需要加油
                while (line<stations[i][0]){
                    if (que.empty())    //无油可加
                        return -1;
                    line+=que.top(),que.pop(),cnt++;
                }
                que.push(stations[i][1]);
            }
        while (line<target){
            if (que.empty())    //无油可加
                return -1;
                line+=que.top(),que.pop(),cnt++;
        }
        return cnt;
    }
};

 

标签:temp,stations,int,long,871,加油站,startFuel,Leetcode,dp
来源: https://www.cnblogs.com/wegret/p/16438280.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有