|
| 1 | +// https://leetcode.com/problems/minimum-cost-to-reach-city-with-discounts |
| 2 | +// T: O((N * K + E) log(N * K)) |
| 3 | +// S: O(N * K + E) |
| 4 | + |
| 5 | +import java.util.Arrays; |
| 6 | +import java.util.Comparator; |
| 7 | +import java.util.HashMap; |
| 8 | +import java.util.Map; |
| 9 | +import java.util.PriorityQueue; |
| 10 | +import java.util.Queue; |
| 11 | + |
| 12 | +public class MinimumCostToReachCityWithDiscounts { |
| 13 | + private record Info(int vertex, int cost, int discounts) {} |
| 14 | + |
| 15 | + public static int minimumCost(int n, int[][] highways, int discounts) { |
| 16 | + final Map<Integer, Map<Integer, Integer>> graph = createGraph(highways); |
| 17 | + final int[][] minCosts = dijkstra(n, graph, discounts); |
| 18 | + return minCost(minCosts[n -1]); |
| 19 | + } |
| 20 | + |
| 21 | + // N = n, K = |discounts|, E |
| 22 | + // T: O(N * K + E log(N * K)) = O((N * K + E) log(N * K)) |
| 23 | + // S: O(N * K + E) |
| 24 | + private static int[][] dijkstra(int n, Map<Integer, Map<Integer, Integer>> graph, int discount) { |
| 25 | + final int[][] dp = initializeDp(n, discount); |
| 26 | + final Queue<Info> queue = new PriorityQueue<>(Comparator.comparingInt(a -> a.cost)); |
| 27 | + queue.add(new Info(0, 0, discount)); |
| 28 | + |
| 29 | + while (!queue.isEmpty()) { |
| 30 | + final Info info = queue.poll(); |
| 31 | + if (dp[info.vertex][info.discounts] <= info.cost) { |
| 32 | + continue; |
| 33 | + } |
| 34 | + |
| 35 | + dp[info.vertex][info.discounts] = info.cost; |
| 36 | + |
| 37 | + for (Map.Entry<Integer, Integer> entry : graph.getOrDefault(info.vertex, new HashMap<>()).entrySet()) { |
| 38 | + final int vertex = entry.getKey(), cost = entry.getValue(); |
| 39 | + queue.add(new Info(vertex, info.cost + cost, info.discounts)); |
| 40 | + if (info.discounts > 0) { |
| 41 | + queue.add(new Info(vertex, info.cost + cost / 2, info.discounts - 1)); |
| 42 | + } |
| 43 | + } |
| 44 | + } |
| 45 | + |
| 46 | + return dp; |
| 47 | + } |
| 48 | + |
| 49 | + private static int[][] initializeDp(int n, int discounts) { |
| 50 | + final int[][] dp = new int[n][discounts + 1]; |
| 51 | + for (int[] row : dp) { |
| 52 | + Arrays.fill(row, Integer.MAX_VALUE); |
| 53 | + } |
| 54 | + return dp; |
| 55 | + } |
| 56 | + |
| 57 | + private static int minCost(int[] array) { |
| 58 | + final int result = Arrays.stream(array).min().getAsInt(); |
| 59 | + if (result == Integer.MAX_VALUE) { |
| 60 | + return -1; |
| 61 | + } |
| 62 | + return result; |
| 63 | + } |
| 64 | + |
| 65 | + private static Map<Integer, Map<Integer, Integer>> createGraph(int[][] edges) { |
| 66 | + final Map<Integer, Map<Integer, Integer>> graph = new HashMap<>(); |
| 67 | + for (int[] edge : edges) { |
| 68 | + final int from = edge[0], to = edge[1], cost = edge[2]; |
| 69 | + final Map<Integer, Integer> fromNeighbours = graph.getOrDefault(from, new HashMap<>()); |
| 70 | + final Map<Integer, Integer> toNeighbours = graph.getOrDefault(to, new HashMap<>()); |
| 71 | + fromNeighbours.put(to, cost); |
| 72 | + toNeighbours.put(from, cost); |
| 73 | + graph.putIfAbsent(from, fromNeighbours); |
| 74 | + graph.putIfAbsent(to, toNeighbours); |
| 75 | + } |
| 76 | + return graph; |
| 77 | + } |
| 78 | +} |
0 commit comments