其他分享
首页 > 其他分享> > Leetcode 871.最低加油次数(dp / 贪心+优先队列)

Leetcode 871.最低加油次数(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