Open In App

Shortest path between two cities without running out of fuel

Last Updated : 29 Feb, 2024
Improve
Improve
Like Article
Like
Save
Share
Report

Given a country with N cities connected by M bi-directional roads given in the form of 2D array roads[][], where P cities have fuel stations and (N – P) cities do not. The task is to compute the shortest path from City A to City B, such that a car with maximum fuel capacity of “capacity” can travel without running out of fuel.

Note: 1 unit of fuel is used to travel through any road.

Examples:

Input: N = 7, M = 6, roads = [[1, 2], [2, 3], [3, 4], [4, 5], [4, 6], [6, 7]], A = 1, B = 7, capacity = 4, P = 1, fuel stations = [5]

Shortest-Path-from-source-to-destination

graph

Output: 7
Explanation: As the shortest path is 1-2-3-4-5-4-6-7

Input: N = 7, M = 6, roads = [[1, 2], [2, 3], [3, 4], [4, 5], [4, 6], [6, 7]], A = 1, B = 7, capacity = 4, P = 2, fuel stations = [5,6]
Output: 5
Explanation: As the shortest path is 1-2-3-4-6-7

Approach: To solve the problem, follow the below idea:

We can solve the problem using Breadth First Search. Start a BFS from source node by pushing the current node along with the remaining fuel in the queue. If at any node, the fuel goes to 0, we eliminate that path i.e. we don’t add that node’s neighbors in the queue again. At the end return the path which takes you to destination while maintaining the fuel capacity.

Step-by-step algorithm:

  1. Build Adjacency List:
    Create an empty list (adj) for the adjacency list.
    Iterate over bi-directional roads and add edges to the adjacency list.
  2. Initialize Capacity Array:
    Create an array (caps) to represent fuel capacity at each city.
    Mark cities with fuel stations by setting caps[city] = capacity.
  3. Initialize Fuel Array:
    Create an array (fuel) to represent the current fuel level at each city.
    Mark the starting city with the full fuel capacity.
  4. Initialize Queue for BFS: Create a deque (que) and add the starting city with distance 0.
  5. Apply BFS:
    Use a while loop to iterate until the queue is empty.
    Pop a pair (distance, node) from the queue.
    If the current node is the destination, return the distance.
    Iterate over neighbors of the current node, updating their fuel levels under certain conditions.
    If the condition is true, update the fuel level and enqueue the neighbor with an incremented distance.
  6. Return -1 if Path Not Found: If the loop completes without reaching the destination, return -1, indicating no path.

Below is the implementation of the algorithm:

C++




#include <iostream>
#include <vector>
#include <queue>
#include <algorithm>
 
using namespace std;
 
class Solution {
public:
    int findMinRoute(int n, vector<vector<int>>& roads, vector<int>& fuelStations, int source, int destination, int capacity) {
        // Defining the adjacency list
        vector<vector<int>> adj(n + 1, vector<int>());
 
        // Building the adjacency list from given roads
        for (auto& road : roads) {
            int u = road[0];
            int v = road[1];
            adj[u].push_back(v);
            adj[v].push_back(u);
        }
 
        // Initializing fuel capacities for each node
        vector<int> caps(n + 1, 0);
        for (int node : fuelStations) {
            caps[node] = capacity;
        }
 
        // Initializing fuel levels for each node
        vector<int> fuel(n + 1, 0);
 
        // Initializing the queue for BFS traversal
        queue<pair<int, int>> queue;
        queue.push({0, source});
        fuel = capacity;
 
        // BFS traversal
        while (!queue.empty()) {
            auto current = queue.front();
            queue.pop();
            int dis = current.first;
            int node = current.second;
 
            if (node == destination) {
                return dis;
            }
 
            // Exploring neighbors of the current node
            for (int adjNode : adj[node]) {
                // Calculating the new fuel level for the adjacent node
                int newFuel = max(caps[adjNode], fuel[node] - 1);
 
                // If the new fuel level is greater than the existing at the next node
                if (newFuel > fuel[adjNode]) {
                    // Update the fuel level and add the adjacent node to the queue
                    fuel[adjNode] = newFuel;
                    queue.push({dis + 1, adjNode});
                }
            }
        }
 
        // If destination is not reachable
        return -1;
    }
};
 
// Example usage
int main() {
    int n = 7;
    vector<vector<int>> roads = {{1, 2}, {2, 3}, {3, 4}, {4, 5}, {4, 6}, {6, 7}};
    int source = 1;
    int destination = 7;
    int capacity = 4;
    vector<int> fuelStations = {5};
    cout << Solution().findMinRoute(n, roads, fuelStations, source, destination, capacity) << endl;
 
    return 0;
}


Java




import java.util.*;
 
class Solution {
    public int findMinRoute(int n, int[][] roads, List<Integer> fuelStations, int source, int destination, int capacity) {
        // Defining the adjacency list
        List<List<Integer>> adj = new ArrayList<>();
        for (int i = 0; i <= n; i++) {
            adj.add(new ArrayList<>());
        }
 
        // Building the adjacency list from given roads
        for (int[] road : roads) {
            int u = road[0];
            int v = road[1];
            adj.get(u).add(v);
            adj.get(v).add(u);
        }
 
        // Initializing fuel capacities for each node
        int[] caps = new int[n + 1];
        for (int node : fuelStations) {
            caps[node] = capacity;
        }
 
        // Initializing fuel levels for each node
        int[] fuel = new int[n + 1];
 
        // Initializing the queue for BFS traversal
        Queue<int[]> queue = new LinkedList<>();
        queue.offer(new int[]{0, source});
        fuel = capacity;
 
        // BFS traversal
        while (!queue.isEmpty()) {
            int[] current = queue.poll();
            int dis = current[0];
            int node = current[1];
 
            if (node == destination) {
                return dis;
            }
 
            // Exploring neighbors of the current node
            for (int adjNode : adj.get(node)) {
                // Calculating the new fuel level for the adjacent node
                int newFuel = Math.max(caps[adjNode], fuel[node] - 1);
 
                // If the new fuel level is greater than the existing at the next node
                if (newFuel > fuel[adjNode]) {
                    // Update the fuel level and add the adjacent node to the queue
                    fuel[adjNode] = newFuel;
                    queue.offer(new int[]{dis + 1, adjNode});
                }
            }
        }
 
        // If destination is not reachable
        return -1;
    }
 
    // Example usage
    public static void main(String[] args) {
        int n = 7;
        int[][] roads = {{1, 2}, {2, 3}, {3, 4}, {4, 5}, {4, 6}, {6, 7}};
        int source = 1;
        int destination = 7;
        int capacity = 4;
        List<Integer> fuelStations = Arrays.asList(5);
        System.out.println(new Solution().findMinRoute(n, roads, fuelStations, source, destination, capacity));
    }
}
 
// This code is contributed by shivamgupta0987654321


C#




using System;
using System.Collections.Generic;
using System.Linq;
 
class Solution
{
    public int FindMinRoute(int n, int[][] roads, List<int> fuelStations, int source, int destination, int capacity)
    {
        // Defining the adjacency list
        List<List<int>> adj = new List<List<int>>();
        for (int i = 0; i <= n; i++)
        {
            adj.Add(new List<int>());
        }
 
        // Building the adjacency list from given roads
        foreach (var road in roads)
        {
            int u = road[0];
            int v = road[1];
            adj[u].Add(v);
            adj[v].Add(u);
        }
 
        // Initializing fuel capacities for each node
        int[] caps = new int[n + 1];
        foreach (int node in fuelStations)
        {
            caps[node] = capacity;
        }
 
        // Initializing fuel levels for each node
        int[] fuel = new int[n + 1];
 
        // Initializing the queue for BFS traversal
        Queue<int[]> queue = new Queue<int[]>();
        queue.Enqueue(new int[] { 0, source });
        fuel = capacity;
 
        // BFS traversal
        while (queue.Count > 0)
        {
            int[] current = queue.Dequeue();
            int dis = current[0];
            int node = current[1];
 
            if (node == destination)
            {
                return dis;
            }
 
            // Exploring neighbors of the current node
            foreach (int adjNode in adj[node])
            {
                // Calculating the new fuel level for the adjacent node
                int newFuel = Math.Max(caps[adjNode], fuel[node] - 1);
 
                // If the new fuel level is greater than the existing at the next node
                if (newFuel > fuel[adjNode])
                {
                    // Update the fuel level and add the adjacent node to the queue
                    fuel[adjNode] = newFuel;
                    queue.Enqueue(new int[] { dis + 1, adjNode });
                }
            }
        }
 
        // If destination is not reachable
        return -1;
    }
 
    // Example usage
    public static void Main(string[] args)
    {
        int n = 7;
        int[][] roads = { new int[] { 1, 2 }, new int[] { 2, 3 }, new int[] { 3, 4 }, new int[] { 4, 5 }, new int[] { 4, 6 }, new int[] { 6, 7 } };
        int source = 1;
        int destination = 7;
        int capacity = 4;
        List<int> fuelStations = new List<int> { 5 };
        Console.WriteLine(new Solution().FindMinRoute(n, roads, fuelStations, source, destination, capacity));
    }
}


Javascript




class Solution {
    findMinRoute(n, roads, fuelStations, source, destination, capacity) {
        // Defining the adjacency list
        const adj = new Array(n + 1).fill(null).map(() => []);
 
        // Building the adjacency list from given roads
        for (const [u, v] of roads) {
            adj[u].push(v);
            adj[v].push(u);
        }
 
        // Initializing fuel capacities for each node
        const caps = new Array(n + 1).fill(0);
        for (const node of fuelStations) {
            caps[node] = capacity;
        }
 
        // Initializing fuel levels for each node
        const fuel = new Array(n + 1).fill(0);
 
        // Initializing the queue for BFS traversal
        const queue = [];
        queue.push([0, source]);
        fuel = capacity;
 
        // BFS traversal
        while (queue.length > 0) {
            const [dis, node] = queue.shift();
 
            if (node === destination) {
                return dis;
            }
 
            // Exploring neighbors of the current node
            for (const adjNode of adj[node]) {
                // Calculating the new fuel level for the adjacent node
                const newFuel = Math.max(caps[adjNode], fuel[node] - 1);
 
                // If the new fuel level is greater than the existing at the next node
                if (newFuel > fuel[adjNode]) {
                    // Update the fuel level and add the adjacent node to the queue
                    fuel[adjNode] = newFuel;
                    queue.push([dis + 1, adjNode]);
                }
            }
        }
 
        // If destination is not reachable
        return -1;
    }
}
 
// Example usage
const n = 7;
const roads = [[1, 2], [2, 3], [3, 4], [4, 5], [4, 6], [6, 7]];
const source = 1;
const destination = 7;
const capacity = 4;
const fuelStations = [5];
console.log(new Solution().findMinRoute(n, roads, fuelStations, source, destination, capacity));


Python3




from collections import deque
 
 
class Solution:
    def findMinRoute(self, n, roads, fuel_stations, source, destination, capacity):
        # Defining the adjacency list
        adj = [[] for _ in range(n + 1)]
 
        # Building the adjacency list from given roads
        for u, v in roads:
            adj[u].append(v)
            adj[v].append(u)
 
        # Initializing fuel capacities for each node
        caps = [0] * (n + 1)
        for node in fuel_stations:
            caps[node] = capacity
 
        # Initializing fuel levels for each node
        fuel = [0] * (n + 1)
 
        # Initializing the queue for BFS traversal
        que = deque([(0, source)])
        fuel = capacity
 
        # BFS traversal
        while que:
            dis, node = que.popleft()
            if node == destination:
                return dis
 
            # Exploring neighbors of the current node
            for adjNode in adj[node]:
                # Calculating the new fuel level for the adjacent node
                new = max(caps[adjNode], fuel[node] - 1)
 
                # If the new fuel level is greater than the existing at the next node
                if new > fuel[adjNode]:
                    # Update the fuel level and add the adjacent node to the queue
                    fuel[adjNode] = new
                    que.append((dis + 1, adjNode))
 
        # If destination is not reachable
        return -1
 
 
# Example usage
n = 7
roads = [[1, 2], [2, 3], [3, 4], [4, 5], [4, 6], [6, 7]]
A = 1
B = 7
capacity = 4
fuel_stations = [5]
print(Solution().findMinRoute(n, roads, fuel_stations, A, B, capacity))


Output

7

Time Complexity: O(N + M) where N is the number of cities and M is the number of roads.
Auxiliary Space: O(N)



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads