📜  找到第一个访问所有汽油泵的循环之旅

📅  最后修改于: 2022-05-13 01:57:01.084000             🧑  作者: Mango

找到第一个访问所有汽油泵的循环之旅

假设有一个圆。在那个圆圈上有 n 个汽油泵。给你两组数据。

  1. 每个汽油泵的汽油量。
  2. 从那个汽油泵到下一个汽油泵的距离。

计算卡车能够完成圆圈的第一个点(卡车将停在每个汽油泵处,它的容量是无限的)。预期时间复杂度为 O(n)。假设使用 1 升汽油,卡车可以行驶 1 个单位的距离。
例如,假设有 4 个汽油泵,汽油量和到下一个汽油泵的距离值对为 {4, 6}, {6, 5}, {7, 3} 和 {4, 5}。卡车可以循环行驶的第一个点是第二个汽油泵。输出应为“start = 1”(第二个汽油泵的索引)。

如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程学生竞争性编程现场课程。

一个简单的解决方案是将每个汽油泵视为起点,看看是否有可能的游览。如果我们找到一个具有可行解的起点,我们就会返回该起点。该解决方案的最坏情况时间复杂度为 O(n^2)。
一种有效的方法是使用 Queue来存储当前游览。我们首先将第一个汽油泵排入队列,我们继续将汽油泵排入队列,直到我们完成游览,或者当前的汽油量变为负数。如果数量变为负数,那么我们将继续使加油泵出列,直到队列变空。
我们没有创建单独的队列,而是使用给定的数组本身作为队列。我们维护两个索引变量 start 和 end,代表队列的后部和前部。



下图是上述方法的试运行:

下面是上述方法的实现:

C++
// C++ program to find circular tour for a truck
#include 
using namespace std;
 
// A petrol pump has petrol and distance to next petrol pump
class petrolPump
{
    public:
    int petrol;
    int distance;
};
 
// The function returns starting point if there is a possible solution,
// otherwise returns -1
int printTour(petrolPump arr[], int n)
{
    // Consider first petrol pump as a starting point
    int start = 0;
    int end = 1;
 
    int curr_petrol = arr[start].petrol - arr[start].distance;
 
    /* Run a loop while all petrol pumps are not visited.
    And we have reached first petrol pump again with 0 or more petrol */
    while (end != start || curr_petrol < 0)
    {
        // If curremt amount of petrol in truck becomes less than 0, then
        // remove the starting petrol pump from tour
        while (curr_petrol < 0 && start != end)
        {
            // Remove starting petrol pump. Change start
            curr_petrol -= arr[start].petrol - arr[start].distance;
            start = (start + 1) % n;
 
            // If 0 is being considered as start again, then there is no
            // possible solution
            if (start == 0)
            return -1;
        }
 
        // Add a petrol pump to current tour
        curr_petrol += arr[end].petrol - arr[end].distance;
 
        end = (end + 1) % n;
    }
 
    // Return starting point
    return start;
}
 
// Driver code
int main()
{
    petrolPump arr[] = {{6, 4}, {3, 6}, {7, 3}};
 
    int n = sizeof(arr)/sizeof(arr[0]);
    int start = printTour(arr, n);
 
    (start == -1)? cout<<"No solution": cout<<"Start = "<


C
// C program to find circular tour for a truck
#include 
 
// A petrol pump has petrol and distance to next petrol pump
struct petrolPump
{
  int petrol;
  int distance;
};
 
// The function returns starting point if there is a possible solution,
// otherwise returns -1
int printTour(struct petrolPump arr[], int n)
{
    // Consider first petrol pump as a starting point
    int start = 0;
    int end =  1;
 
    int curr_petrol = arr[start].petrol - arr[start].distance;
 
    /* Run a loop while all petrol pumps are not visited.
      And we have reached first petrol pump again with 0 or more petrol */
    while (end != start || curr_petrol < 0)
    {
        // If curremt amount of petrol in truck becomes less than 0, then
        // remove the starting petrol pump from tour
        while (curr_petrol < 0 && start != end)
        {
            // Remove starting petrol pump. Change start
            curr_petrol -= arr[start].petrol - arr[start].distance;
            start = (start + 1)%n;
 
            // If 0 is being considered as start again, then there is no
            // possible solution
            if (start == 0)
               return -1;
        }
 
        // Add a petrol pump to current tour
        curr_petrol += arr[end].petrol - arr[end].distance;
 
        end = (end + 1)%n;
    }
 
    // Return starting point
    return start;
}
 
// Driver program to test above functions
int main()
{
    struct petrolPump arr[] = {{6, 4}, {3, 6}, {7, 3}};
 
    int n = sizeof(arr)/sizeof(arr[0]);
    int start = printTour(arr, n);
 
    (start == -1)? printf("No solution"): printf("Start = %d", start);
 
    return 0;
}


Java
//Java program to find circular tour for a truck
 
public class Petrol
{
    // A petrol pump has petrol and distance to next petrol pump
    static class petrolPump
    {
        int petrol;
        int distance;
         
        // constructor
        public petrolPump(int petrol, int distance)
        {
            this.petrol = petrol;
            this.distance = distance;
        }
    }
     
    // The function returns starting point if there is a possible solution,
    // otherwise returns -1
    static int printTour(petrolPump arr[], int n)
    { 
        int start = 0;
        int end = 1;
        int curr_petrol = arr[start].petrol - arr[start].distance;
         
        // If current amount of petrol in truck becomes less than 0, then
        // remove the starting petrol pump from tour
        while(end != start || curr_petrol < 0)
        {
             
            // If current amount of petrol in truck becomes less than 0, then
            // remove the starting petrol pump from tour
            while(curr_petrol < 0 && start != end)
            {
                // Remove starting petrol pump. Change start
                curr_petrol -= arr[start].petrol - arr[start].distance;
                start = (start + 1) % n;
                 
                // If 0 is being considered as start again, then there is no
                // possible solution
                if(start == 0)
                    return -1;
            }
            // Add a petrol pump to current tour
            curr_petrol += arr[end].petrol - arr[end].distance;
             
            end = (end + 1)%n;
        }
         
        // Return starting point
        return start;
    }
     
    // Driver program to test above functions
    public static void main(String[] args)
    {
         
        petrolPump[] arr = {new petrolPump(6, 4),
                            new petrolPump(3, 6),
                            new petrolPump(7, 3)};
         
        int start = printTour(arr, arr.length);
         
        System.out.println(start == -1 ? "No Solution" : "Start = " + start);
 
    }
 
}
//This code is contributed by Sumit Ghosh


Python
# Python program to find circular tour for a truck
# In this approach we will start the tour from the first petrol pump
# then while moving to the next pumps in the loop we will store the cumulative
# information that whether we have a deficit of petrol at the current pump or not
# If there is a deficit then we will add it to the deficit value calculated
# till the previous petrol pump and then update the starting point to the next pump
# and reset the petrol available in the truck as 0
 
# This function return starting point if there is a possible
# solution otherwise returns -1
def printTour(arr,n):
     
    # Consider first petrol pump as starting point
    start = 0
    # These two variable will keep tracking if there is
    # surplus(s) or deficit(d) of petrol in the truck
    s = 0          # petrol available the truck till now
    d = 0        # deficit of petrol till visiting this petrol pump
     
    # Start from the first petrol pump and complete one loop
    # of visiting all the petrol pumps and keep updating s and d at each pump
    for i in range(n):
      s += arr[i][0] - arr[i][1]
      if s < 0:            # the truck has a deficit of petrol
        start = i+1        # change the starting point
        d += s            # storing the deficit of petrol till current petrol pump
        s = 0            # starting again from new station
     
    # when we reach first petrol pump again and sum of the petrol available at the truck
    # and the petrol deficit till now is 0 or more petrol then return the starting point
    # else return -1
    return start if (s+d)>=0 else -1
   
   
# Driver program to test above function
arr = [[6,4], [3,6], [7,3]]
start = printTour(arr,3)
if start == -1:
  print("No Solution Possible !!!")
else:
  print("start = {}".format(start))
 
# This code is contributed by Antara Das(anny)


C#
// C# program to find circular
// tour for a truck
using System;
 
class GFG
{
    // A petrol pump has petrol and
    // distance to next petrol pump
    public class petrolPump
    {
        public int petrol;
        public int distance;
 
        // constructor
        public petrolPump(int petrol,
                          int distance)
        {
            this.petrol = petrol;
            this.distance = distance;
        }
    }
 
    // The function returns starting point
    // if there is a possible solution,
    // otherwise returns -1
    public static int printTour(petrolPump[] arr,
                                int n)
    {
        int start = 0;
        int end = 1;
        int curr_petrol = arr[start].petrol -
                          arr[start].distance;
 
        // If current amount of petrol in 
        // truck becomes less than 0, then
        // remove the starting petrol pump from tour
        while (end != start || curr_petrol < 0)
        {
 
            // If current amount of petrol in
            // truck becomes less than 0, then
            // remove the starting petrol pump from tour
            while (curr_petrol < 0 && start != end)
            {
                // Remove starting petrol pump.
                // Change start
                curr_petrol -= arr[start].petrol -
                               arr[start].distance;
                start = (start + 1) % n;
 
                // If 0 is being considered as
                // start again, then there is no
                // possible solution
                if (start == 0)
                {
                    return -1;
                }
            }
             
            // Add a petrol pump to current tour
            curr_petrol += arr[end].petrol -
                           arr[end].distance;
 
            end = (end + 1) % n;
        }
 
        // Return starting point
        return start;
    }
 
    // Driver Code
    public static void Main(string[] args)
    {
        petrolPump[] arr = new petrolPump[]
        {
            new petrolPump(6, 4),
            new petrolPump(3, 6),
            new petrolPump(7, 3)
        };
 
        int start = printTour(arr, arr.Length);
 
        Console.WriteLine(start == -1 ? "No Solution" :
                                   "Start = " + start);
    }
}
 
// This code is contributed by Shrikant13


Javascript


C++
// C++ program to find circular tour for a truck
#include 
using namespace std;
 
// A petrol pump has petrol and distance to next petrol pump
class petrolPump {
public:
    int petrol;
    int distance;
};
 
// The function returns starting point if there is a
// possible solution, otherwise returns -1
int printTour(petrolPump arr[], int n)
{
    int start;
 
    for (int i = 0; i < n; i++) {
        // Identify the first petrol pump from where we
        // might get a full circular tour
        if (arr[i].petrol >= arr[i].distance) {
            start = i;
            break;
        }
    }
 
    // To store the excess petrol
    int curr_petrol = 0;
 
    int i;
 
    for (i = start; i < n;) {
 
        curr_petrol += (arr[i].petrol - arr[i].distance);
 
        // If at any point remaining petrol is less than 0,
        // it means that we cannot start our journey from
        // current start
        if (curr_petrol < 0) {
 
            // We move to the next petrol pump
            i++;
 
            // We try to identify the next petrol pump from
            // where we might get a full circular tour
            for (; i < n; i++) {
                if (arr[i].petrol >= arr[i].distance) {
 
                    start = i;
 
                    // Reset rem_petrol
                    curr_petrol = 0;
 
                    break;
                }
            }
        }
 
        else {
            // Move to the next petrolpump if curr_petrol is
            // >= 0
            i++;
        }
    }
 
    // If remaining petrol is less than 0 while we reach the
    // first petrol pump, it means no circular tour is
    // possible
    if (curr_petrol < 0) {
        return -1;
    }
 
    for (int j = 0; j < start; j++) {
 
        curr_petrol += (arr[j].petrol - arr[j].distance);
 
        // If remaining petrol is less than 0 at any point
        // before we reach initial start, it means no
        // circular tour is possible
        if (curr_petrol < 0) {
            return -1;
        }
    }
 
    // If we have successfully reached intial_start, it
    // means can get a circular tour from final_start, hence
    // return it
    return start;
}
// Driver code
int main()
{
    petrolPump arr[] = { { 6, 4 }, { 3, 6 }, { 7, 3 } };
 
    int n = sizeof(arr) / sizeof(arr[0]);
    int start = printTour(arr, n);
 
    (start == -1) ? cout << "No solution"
                  : cout << "Start = " << start;
 
    return 0;
}
 
// This code is contributed by supratik_mitra


Javascript


输出:

start = 2

时间复杂度:我们只访问每个汽油泵一次,因此时间复杂度为O(n)

辅助空间: O(1)

另一个有效的解决方案可以是找出第一个汽油泵,其中汽油量大于或等于到达下一个汽油泵所需的距离。现在我们将该汽油泵标记为开始,现在我们检查是否可以完成通往终点的旅程。如果在中间,在任何一个加油站,加油量小于到达下一个加油站的距离,那么我们可以说我们不能从一开始就完成循环。我们再次尝试找出可以开始旅程的下一个点,即下一个加油量大于或等于要行驶的距离的加油站,我们将其标记为start 。我们不需要查看标记为启动的初始汽油泵和新启动之间的任何汽油泵,因为我们知道如果我们从任何中间的汽油泵开始,我们将无法完成旅程,因为最终我们会到达一个点小于距离。现在我们重复这个过程,直到我们到达最后一个汽油泵,并在需要时更新我们的开始。在我们到达最后一个汽油泵后,我们尝试从最后一个汽油泵到达我们的第一个汽油泵,假设我们还有剩余的汽油量作为curr_petrol 。现在我们再次从第一个汽油泵开始行驶,并利用我们的curr_petrol并尝试到达start 。如果我们能够到达起点,那么我们可以得出结论,起点可以成为我们的起点。

下面是上述方法的实现:

C++

// C++ program to find circular tour for a truck
#include 
using namespace std;
 
// A petrol pump has petrol and distance to next petrol pump
class petrolPump {
public:
    int petrol;
    int distance;
};
 
// The function returns starting point if there is a
// possible solution, otherwise returns -1
int printTour(petrolPump arr[], int n)
{
    int start;
 
    for (int i = 0; i < n; i++) {
        // Identify the first petrol pump from where we
        // might get a full circular tour
        if (arr[i].petrol >= arr[i].distance) {
            start = i;
            break;
        }
    }
 
    // To store the excess petrol
    int curr_petrol = 0;
 
    int i;
 
    for (i = start; i < n;) {
 
        curr_petrol += (arr[i].petrol - arr[i].distance);
 
        // If at any point remaining petrol is less than 0,
        // it means that we cannot start our journey from
        // current start
        if (curr_petrol < 0) {
 
            // We move to the next petrol pump
            i++;
 
            // We try to identify the next petrol pump from
            // where we might get a full circular tour
            for (; i < n; i++) {
                if (arr[i].petrol >= arr[i].distance) {
 
                    start = i;
 
                    // Reset rem_petrol
                    curr_petrol = 0;
 
                    break;
                }
            }
        }
 
        else {
            // Move to the next petrolpump if curr_petrol is
            // >= 0
            i++;
        }
    }
 
    // If remaining petrol is less than 0 while we reach the
    // first petrol pump, it means no circular tour is
    // possible
    if (curr_petrol < 0) {
        return -1;
    }
 
    for (int j = 0; j < start; j++) {
 
        curr_petrol += (arr[j].petrol - arr[j].distance);
 
        // If remaining petrol is less than 0 at any point
        // before we reach initial start, it means no
        // circular tour is possible
        if (curr_petrol < 0) {
            return -1;
        }
    }
 
    // If we have successfully reached intial_start, it
    // means can get a circular tour from final_start, hence
    // return it
    return start;
}
// Driver code
int main()
{
    petrolPump arr[] = { { 6, 4 }, { 3, 6 }, { 7, 3 } };
 
    int n = sizeof(arr) / sizeof(arr[0]);
    int start = printTour(arr, n);
 
    (start == -1) ? cout << "No solution"
                  : cout << "Start = " << start;
 
    return 0;
}
 
// This code is contributed by supratik_mitra

Javascript


输出:

start = 2

时间复杂度: O(n)

辅助空间: O(1)