There are n cities connected by some number of flights. You are given an array flights where flights[i] = [fromi, toi, pricei] indicates that there is a flight from city fromi to city toi with cost pricei.
You are also given three integers src, dst, and k, return the cheapest price fromsrctodstwith at mostkstops. If there is no such route, return -1.
Input: n =4, flights =[[0,1,100],[1,2,100],[2,0,100],[1,3,600],[2,3,200]], src =0, dst =3, k =1Output: 700Explanation:
The graph is shown above.The optimal path with at most 1 stop from city 0 to 3is marked in red and has cost 100+600=700.Note that the path through cities [0,1,2,3]is cheaper but is invalid because it uses 2 stops.
Example 2:
graph TD;
A(0) -- "100" --> B(1)
B -- "100" --> C(2)
A -- "500" --> C
linkStyle default stroke:blue
linkStyle 0 stroke-width:4px,stroke:red
linkStyle 1 stroke-width:4px,stroke:red
1
2
3
4
5
Input: n =3, flights =[[0,1,100],[1,2,100],[0,2,500]], src =0, dst =2, k =1Output: 200Explanation:
The graph is shown above.The optimal path with at most 1 stop from city 0 to 2is marked in red and has cost 100+100=200.
Example 3:
graph TD;
A(0) -- "100" --> B(1)
B -- "100" --> C(2)
A -- "500" --> C
linkStyle default stroke:blue
linkStyle 2 stroke-width:4px,stroke:red
1
2
3
4
5
Input: n =3, flights =[[0,1,100],[1,2,100],[0,2,500]], src =0, dst =2, k =0Output: 500Explanation:
The graph is shown above.The optimal path with no stops from city 0 to 2is marked in red and has cost 500.
public Map<Integer, List<int[]>>buildGraph(int[][] flights) {
for (int i = 0; i < n; i++) {
graph.put(i, new LinkedList<>());
}
Map<Integer,List<int[]>> map=new HashMap<>();
for(int[] f:flights) {
// map.putIfAbsent(f[0],new ArrayList<>()); map.get(f[0]).add(newint[]{i[1],i[2]});
}
}
Note that we are running for (i=0; i<n;i++) loop above. The reason is it helps in case when the graph is not connected. If we are sure that graph is connected, we can just remove this loop and uncomment map.putIfAbsent(f[0],new ArrayList<>());.
Now we can use buildGraph across multiple approaches
Pretty straightforward implementation. Traverse all the children of the source upto k stops. If at any point we reach the destination, store the min of the answer and the current cost.
Now the question is why are we passing flights as K+1 to DFS? Because we have K stops at maximum, hence K+1 flights between those stops.
publicintfindCheapestPrice(int n, int[][] flights, int src, int dst, int K) {
Map<Integer, List<int[]>> graph = buildGraph(n, flights);
boolean[] visited =newboolean[n];
// I am passing fare as array object as Java is pass by valueint[] fare =newint[1];
fare[0]= Integer.MAX_VALUE;
//find cheapest price with k stops(k + 1 flights) dfs(graph, src, dst, K+1, fare, 0, visited);
return fare[0]== Integer.MAX_VALUE?-1 : fare[0];
}
privatevoiddfs(Map<Integer, List<int[]>> graph, int src, int dst, int K, int[] fare, int currentCost, boolean[] visited) {
if (K == 0) {
return;
}
if (src == dst) {
fare[0]= Math.min(fare[0], currentCost);
return;
}
visited[src]=true;
for (int[] e : graph.get(src)) {
int eVertex = e[0], eCost = e[1];
//Pruning, check the sum of current price and next cost. if (!visited[eVertex]&& currentCost + eCost <= fare[0]) {
dfs(graph, eVertex, dst, K - 1, fare, currentCost + eCost, visited);
}
}
visited[src]=false;
}
The only thing which appears to be different from a standard DFS call is the memoization part. Since, the nodes are higher in number and we can easily get a TLE re-calculating the distances, it’s better to store the computed values for later use.
So, we now return cost from dfs method. As, we are storing fare in dp array, we dont have to carry fare as well and remove visited set.
Unlike BFS, now we simultaneously traverse all the possible path going out from source for upto k steps. If the ans is found in between, we store the min of the current ans with the newly found one. A modification to the standard bfs design, we pass the starting cost a 0 to the queue as well and go on adding to it.
publicintfindCheapestPrice(int n, int[][] flights, int src, int dst, int K) {
Map<Integer, List<int[]>> graph = buildGraph(n, flights);
int step = 0;
Queue<int[]> q =new LinkedList<>();
q.offer(newint[] {
src, 0
});
int ans = Integer.MAX_VALUE;
while (!q.isEmpty()) {
int size = q.size();
for (int i = 0; i<size; i++) {
int[] curr = q.poll();
if (curr[0]== dst)
ans = Math.min(ans, curr[1]);
if (!map.containsKey(curr[0]))
continue;
for (int[] f: map.get(curr[0])) {
if (curr[1]+ f[1]> ans) //Pruningcontinue;
q.offer(newint[] {
f[0], curr[1]+ f[1] });
}
}
if (step > (K+1)) // again remember, K stops, K+1 flightsbreak;
}
return ans == Integer.MAX_VALUE?-1 : ans;
}