Algorithm for truck moving around a circle of gas stations

前端 未结 11 1369
陌清茗
陌清茗 2020-12-13 07:08

You have a truck moving around a circular track with gas stations spaced out around the circle. Each station has a finite amount of gas. The gas tank on the truck is infinit

相关标签:
11条回答
  • 2020-12-13 08:00

    This is basically the maximum subarray sum problem. On the other hand, we can look at it from somewhat different POV. Let us find out where will we have the most deficiency in the fuel if we start the journey from the very first gas station. Since we know that reaching this point shall take the most of the fuel, we can conclude that the truck has to start at this point to minimize the negative fuell balance. Below is the solution with the driver program with O(N) time and O(1) space complexity and there is no need for any DP, since everything is done in a single pass and using only two integers to store the start point index and its value (though this is needed only for printing purposes).

    #include <stdlib.h>
    #include <stdio.h>
    #include <time.h>
    #include <vector>
    #include <algorithm>
    
    using namespace std;
    
    int gasoline[] = {8, 6, 30, 9, 15, 21, 2, 18};
    int stations[] = {15, 8, 2, 6, 18, 9, 21, 30};
    
    int rnd_num(const int& low, const int& high)
    {
        int rndnum = (int) (((double) rand() / (double) RAND_MAX) * (high - low + 1) + low);
        return rndnum;
    }
    
    void swap(int data[], const int& idxlow, const int& idxhigh)
    {
        int tmp = data[idxlow];
        data[idxlow] = data[idxhigh];
        data[idxhigh] = tmp;
    }
    
    void print_array(const char* label, int data[], int size)
    {
        printf("%-10s: ", label);
        for (int i = 0; i < size; ++i){
            printf("%-3d ", data[i]);
        }
        printf("\n");
    }
    
    void print_vector(const char* label, const vector<int>& data)
    {
        printf("%-10s: ", label);
        for (vector<int>::size_type i = 0; i < data.size(); ++i){
            printf("%-3d ", data[i]);
        }
        printf("\n");
    }
    
    void shuffle(int data[], int size)
    {
        for (int i = 0; i < size - 1; ++i){
            int idx = rnd_num(i + 1, size - 1);
            swap(data, i, idx);
        }
    }
    
    void run(int gas[], int dist[], int size)
    {
        vector<int> path;
        int diff = 0, vidx, minidx = 0, minval = gas[0] - dist[0];
    
        path.resize(size);
    
        for (int i = 0; i < size; ++i) {
            diff += gas[i] - dist[i];
            if (i == size - 1){
                vidx = 0; //path[0] = diff;
            }
            else {
                vidx = i + 1; //path[i + 1] = diff;
            }
    
            path[vidx] = diff;
            if (diff < minval) {
                minval = diff;
                minidx = vidx;
            }
        }
    
        print_vector("PATHS   ", path);
        printf("MINIDX: %d\nMINVAL: %d\n", minidx, minval);
    }
    
    int main()
    {
        int size = sizeof(stations)/sizeof(stations[0]);
        srand((unsigned)time(NULL));
    
        shuffle(gasoline, sizeof(gasoline)/sizeof(gasoline[0]));
        shuffle(stations, sizeof(stations)/sizeof(stations[0]));
    
        print_array("GASOLINE ", gasoline, sizeof(gasoline)/sizeof(gasoline[0]));
        print_array("STATIONS ", stations, sizeof(stations)/sizeof(stations[0]));
    
        run(gasoline, stations, size);
    
        return 0;
    }
    
    0 讨论(0)
  • 2020-12-13 08:03

    Here is my solution in python. Addition to other explained once we keep a variable to calculate the need for the previous stations and when we are at the end of the array we just check if our leftover is above that need and return accordingly.

        if not gas or not cost:
            return - 1
    
        index = 0
        start = 0
        total = 0
        need = 0
        while index < len(gas):
            # If we can travel without any leftover.
            # What is our status since start, if total is
            # below zero that means we are in a worse situation
            # then we were.
            total += gas[index] - cost[index]
            if total < 0 :
                need -= total
                start = index + 1
                total = 0
            index += 1
    
        if total - need >= 0:
            return start
        else:
            return -1
    
    0 讨论(0)
  • 2020-12-13 08:06

    Yes O(n) is possible. Definitely not TSP.

    Let xi be the amount of gas available at station i minus the amount of gas required to go to next station.

    A requirement is Σ xi ≥ 0 (enough gas to complete a full circle).

    Consider Si = x1 + x2 + ... + xi

    Note that Sn ≥ 0.

    Now pick the smallest (or even largest will do, making it easier to write code for) k such that Sk is the least and start at the station next to it.

    Now for k < j ≤ n, we have the gas in tank = Sj - Sk ≥ 0.

    for 1 ≤ j ≤ k, we have gas in tank = xk+1 + .. + xn + x1 + x2 + .. + xj = Sn - Sk + Sj ≥ 0.

    Thus starting at k+1 will ensure there is enough gas accumulated at each station to get to the next station.

    // C++ code. gas[i] is the gas at station i, cost[i] is the cost from station i to (i+1)%n
    int circ(vector<int> &gas, vector<int> &cost) {
        int min_S=INT_MAX, S=0, position=0;
        for(int i=0;i<gas.size();i++)
        {
            S += gas[i] - cost[i];
            if(S<min_S)
            {
                min_S = S;
                position = (i+1) % gas.size();
            }
        }
        if(S>=0)
            return position;
        else
            return -1;
    }
    
    0 讨论(0)
  • 2020-12-13 08:09

    Here's an approach that works in O(n) time and O(1) space (as opposed to O(n) space for Aryabhatta's answer).

    Start at any station, call it station 0, and advance until you run out of gas. If you don't run out of gas, done. Otherwise, if you run out between stations k and k+1, start over again at station k+1. Make a note if you pass 0 again, and if you run out after that it can't be done.

    The reason this works is because if you start at station i and run out of gas between stations k and k+1, then you will also run out of gas before station k+1 if you start at any station between i and k.

    Here's an algorithm, given an arrays P (petrol) and D (distance):

    int position = 0;
    int petrol = P[0];
    int distance = D[0];
    
    int start = 0;
    while (start < n) {
        while (petrol >= distance) {
            petrol += P[++position % N] - distance;
            distance = D[position % N];
            if (position % N == start)
                return start;
        }
        start = position;
        petrol = P[start];
    }
    return -1;
    
    0 讨论(0)
  • 2020-12-13 08:09
    static int getIndex(int A[], int B[]) {
        int start = -1;
        int N = A.length;
        for (int i = 0; i < N; i++) {
            int c = A[i] - B[i];
            if (c >= 0) {
                int j = i + 1;
                while (c >= 0 && j < i + N) {
                    c += A[j % N] - B[j % N];
                    j++;
                }
                if (c >= 0) {
                    start = i;
                    break;
                }
            }
        }
        return start;
    }
    
    0 讨论(0)
提交回复
热议问题