Leetcode 1575. Count All Possible Routes

Problem Explanation

We are asked to count all the possible routes between two cities given an array of locations, a start point, an endpoint, and an initial amount of fuel. The locations array represents the city locations and their respective positions. The fuel we have initially is subtracted with the absolute difference between the locations of city i and city j as we move between the two cities.

The problem requires us to return the total potential routes from our start city to the finish city without our fuel getting negative and each answer should be returned modulo 10^9 + 7.

Approach

The problem can be solved using the Depth-First Search (DFS) + Dynamic Programming (DP) approach. DP will be used to store the solutions of subproblems and reduce the number of redundant calculations. DFS will be used to traverse all the possible routes.

The intuitive approach is to iterate each city and calculate the number of ways to finish from each city using DFS, which however, leads to certain redundant substeps such as the number of ways from i-th city to finish will be recalculated many times.

We maintain a DP table where dp[i][j] represents the total number of paths from the i-th city to the finish city with j units of fuel available.

For example, if we are given

1
2
3locations = [2,3,6,8,4], start = 1, finish = 3, fuel = 5

Our total distinct paths from start to end consuming exactly 5 units of fuel are:

  • 1 -> 3
  • 1 -> 2 -> 3
  • 1 -> 4 -> 3
  • 1 -> 4 -> 2 -> 3

So the answer is 4.

Python Solution

1
2python
3class Solution:
4    def countRoutes(self, locations: List[int], start: int, finish: int, fuel: int) -> int:
5        mod = 10**9 + 7
6        n = len(locations)
7        dp = [[-1 for _ in range(fuel+1)] for _ in range(n)]
8        
9        def dfs(city, remain):
10            # if no more fuel, cannot go further
11            if remain < 0:
12                return 0
13            # if this case has been solved before, use it directly
14            if dp[city][remain] != -1:
15                return dp[city][remain]
16            res = 0
17            # if the current city is the target city, add it
18            if city == finish:
19                res += 1
20            # try to move to any other city
21            for nxt in range(n):
22                if nxt != city:
23                    cost = abs(locations[city] - locations[nxt])
24                    res = (res + dfs(nxt, remain - cost)) % mod
25            dp[city][remain] = res
26            return res
27        
28        return dfs(start, fuel)

Java Solution

1
2java
3class Solution 
4{
5    private static final int MOD = (int) 1e9 + 7;
6    int[][] dp;
7    
8    public int countRoutes(int[] ls, int start, int end, int fuel) 
9    {
10        int n = ls.length;
11        dp = new int[n][fuel + 1];
12        
13        for(int i = 0; i < n; i++) Arrays.fill(dp[i], -1);
14        
15        return dfs(ls, start, end, fuel);
16    }
17    
18    private int dfs(int[] ls, int i, int end, int f)
19    {
20        if (f < 0) return 0;
21        if (dp[i][f] != -1) return dp[i][f];
22        
23        dfs[i][f] = i == end ? 1 : 0;
24        
25        for (int j = 0; j < ls.length; ++j)
26        {
27            if (j == i) continue;
28            
29            dfs[i][f] += dfs(ls, j, end, f - Math.abs(ls[i] - ls[j])) % MOD;
30        }
31        
32        return dp[i][f];
33    }
34}

JavaScript Solution

1
2javascript
3var countRoutes = function(locations, start, finish, fuel) {
4    let mod = 10**9 + 7;
5    let dp = Array.from(Array(locations.length), () => Array(fuel + 1).fill(-1));
6    
7    let dfs = (city, remain) => {
8        if (remain < 0) 
9            return 0;
10        if (dp[city][remain] != -1) 
11            return dp[city][remain];
12        
13        let res = (city == finish);
14        for(let nxt = 0; nxt < locations.length; nxt++){
15            if (nxt == city)
16                continue;
17            res = (res + dfs(nxt, remain - Math.abs(locations[city] - locations[nxt]))) % mod;
18        }
19        return dp[city][remain] = res;
20    };
21    return dfs(start, fuel);
22};

C++ Solution

1
2C++
3class Solution {
4public:
5    int countRoutes(vector<int>& locations, int start, int finish, int fuel) {
6        int MOD = 1000000007;
7        vector<vector<long long>> dp(locations.size(), vector<long long>(201, -1));
8        
9        function<long long (int, int)> dfs = [&](int i, int f) -> long long {
10            if(f < 0) return 0;
11            if(dp[i][f] != -1) return dp[i][f];
12            
13            long long ans = i == finish;
14            for(int j = 0; j < locations.size(); j++)
15                if(i != j)
16                    ans = (ans + dfs(j, f - abs(locations[i] - locations[j]))) % MOD;
17            return dp[i][f] = ans;
18        };
19        return dfs(start, fuel);
20    }
21};

C# Solution

1
2csharp
3public class Solution {
4    public int CountRoutes(int[] locations, int start, int finish, int fuel) {
5        int n = locations.Length;
6        int[, ] dp = new int[n, fuel + 1];
7        
8        for (int i = 0; i < n; i++) {
9            for (int j = 0; j <= fuel; j++) {
10                dp[i, j] = -1;
11            }
12        }
13        
14        return DFS(locations, start, finish, fuel, dp);
15    }
16    
17    private static int MOD = (int) 1e9 + 7;
18    
19    private int DFS(int[] ls, int i, int end, int f, int[, ] dp) {
20        if (f < 0) return 0;
21        if (dp[i, f] != -1) return dp[i, f];
22        
23        dp[i, f] = i == end ? 1 : 0;
24        
25        for (int j = 0; j < ls.Length; ++j) {
26            if (j == i) continue;
27            dp[i, f] = (dp[i, f] + DFS(ls, j, end, f - Math.Abs(ls[i] - ls[j]), dp)) % MOD;
28        }
29        
30        return dp[i, f];
31    }
32}

To summarise, we have solved the problem using the DFS + DP approach, traversing all the possible routes and storing the subproblem solutions for reusability. This way, we finally get the total number of different paths or routes we can take from the start to the finish city considering all the rules provided in the problem.Above, we discussed the problem of counting the possible routes between two cities and shared its solutions in Python, Java, JavaScript, C++ and C#. The algorithm leverages dynamic programming and depth-first search to calculate the possible routes from a start city to an end city without running out of fuel. It does this by storing solutions of respective subproblems and reducing the redundancy of calculations.

However, it's necessary to note that the problem gets significantly complex as the number of cities increase, leading to an expanded search space and subsequently more computations. In such cases, optimization would require strategic selection of which paths to explore and which to cut off early depending on factors such as fuel constraints and distance of cities.

For optimization, one could implement heuristics to guide the search process or use advanced optimization techniques like branch and bound or genetic algorithms, subject to the problem's constraints and requirements.

In conclusion, the proposed solutions showcase the application of fundamental and efficient problem-solving techniques of DFS and Dynamic Programming in route planning problems, with the potential of optimization based on specific factors.


Got a question? Ask the Teaching Assistant anything you don't understand.

Still not clear? Ask in the Forum,  Discord or Submit the part you don't understand to our editors.


TA 👨‍🏫