Minimum Cost to Buy Apples

medium graph dijkstra shortest path

Problem

You are given n cities numbered 1..n, a list of undirected roads where [a, b, w] means travelling between city a and city b costs w, an array appleCost where appleCost[i] is the price of one apple in city i+1, and an integer k. Starting from a city, every road you walk on the way out costs its weight, and every road on the way back costs k times its weight. For each starting city, find the minimum total cost to buy exactly one apple somewhere and return home. Return an array answer where answer[i] is that minimum for starting city i+1.

Buying at city j from start s costs appleCost[j] + (k + 1) · dist(s, j), since the round trip pays the road weights once on the way out and k times on the way back.

Inputn = 4, roads = [[1,2,4],[2,3,2],[2,4,5],[3,4,1],[1,3,4]], appleCost = [56,42,102,301], k = 2
Output[54, 42, 48, 51]
From city 1 the cheapest plan is to walk to city 2 (dist 4) and buy there: 42 + (2 + 1) · 4 = 42 + 12 = 54. From city 2 you simply buy at home: 42 + 0 = 42.

import heapq

def min_cost(n, roads, apple_cost, k):
    adj = [[] for _ in range(n + 1)]
    for a, b, w in roads:
        adj[a].append((b, w))
        adj[b].append((a, w))

    def dijkstra(src):
        dist = [float('inf')] * (n + 1)
        dist[src] = 0
        pq = [(0, src)]
        best = apple_cost[src - 1]
        while pq:
            d, u = heapq.heappop(pq)
            if d > dist[u]:
                continue
            best = min(best, apple_cost[u - 1] + (k + 1) * d)
            for v, w in adj[u]:
                nd = d + w
                if nd < dist[v]:
                    dist[v] = nd
                    heapq.heappush(pq, (nd, v))
        return best

    return [dijkstra(s) for s in range(1, n + 1)]
function minCost(n, roads, appleCost, k) {
  const adj = Array.from({ length: n + 1 }, () => []);
  for (const [a, b, w] of roads) {
    adj[a].push([b, w]);
    adj[b].push([a, w]);
  }
  function dijkstra(src) {
    const dist = new Array(n + 1).fill(Infinity);
    dist[src] = 0;
    const pq = [[0, src]];
    let best = appleCost[src - 1];
    while (pq.length) {
      pq.sort((x, y) => x[0] - y[0]);
      const [d, u] = pq.shift();
      if (d > dist[u]) continue;
      best = Math.min(best, appleCost[u - 1] + (k + 1) * d);
      for (const [v, w] of adj[u]) {
        const nd = d + w;
        if (nd < dist[v]) { dist[v] = nd; pq.push([nd, v]); }
      }
    }
    return best;
  }
  const ans = [];
  for (let s = 1; s <= n; s++) ans.push(dijkstra(s));
  return ans;
}
class Solution {
    public int[] minCost(int n, int[][] roads, int[] appleCost, int k) {
        List<int[]>[] adj = new List[n + 1];
        for (int i = 0; i <= n; i++) adj[i] = new ArrayList<>();
        for (int[] r : roads) {
            adj[r[0]].add(new int[]{ r[1], r[2] });
            adj[r[1]].add(new int[]{ r[0], r[2] });
        }
        int[] ans = new int[n];
        for (int s = 1; s <= n; s++) ans[s - 1] = dijkstra(s, n, adj, appleCost, k);
        return ans;
    }

    private int dijkstra(int src, int n, List<int[]>[] adj, int[] appleCost, int k) {
        long[] dist = new long[n + 1];
        Arrays.fill(dist, Long.MAX_VALUE);
        dist[src] = 0;
        PriorityQueue<long[]> pq = new PriorityQueue<>((x, y) -> Long.compare(x[0], y[0]));
        pq.add(new long[]{ 0, src });
        long best = appleCost[src - 1];
        while (!pq.isEmpty()) {
            long[] top = pq.poll();
            long d = top[0]; int u = (int) top[1];
            if (d > dist[u]) continue;
            best = Math.min(best, appleCost[u - 1] + (long)(k + 1) * d);
            for (int[] e : adj[u]) {
                long nd = d + e[1];
                if (nd < dist[e[0]]) { dist[e[0]] = nd; pq.add(new long[]{ nd, e[0] }); }
            }
        }
        return (int) best;
    }
}
vector<int> minCost(int n, vector<vector<int>>& roads, vector<int>& appleCost, int k) {
    vector<vector<pair<int,int>>> adj(n + 1);
    for (auto& r : roads) {
        adj[r[0]].push_back({ r[1], r[2] });
        adj[r[1]].push_back({ r[0], r[2] });
    }
    auto dijkstra = [&](int src) -> long long {
        vector<long long> dist(n + 1, LLONG_MAX);
        dist[src] = 0;
        priority_queue<pair<long long,int>, vector<pair<long long,int>>, greater<>> pq;
        pq.push({ 0, src });
        long long best = appleCost[src - 1];
        while (!pq.empty()) {
            auto [d, u] = pq.top(); pq.pop();
            if (d > dist[u]) continue;
            best = min(best, (long long)appleCost[u - 1] + (long long)(k + 1) * d);
            for (auto& e : adj[u]) {
                long long nd = d + e.second;
                if (nd < dist[e.first]) { dist[e.first] = nd; pq.push({ nd, e.first }); }
            }
        }
        return best;
    };
    vector<int> ans;
    for (int s = 1; s <= n; s++) ans.push_back((int)dijkstra(s));
    return ans;
}
Time: O(n · (V + E) log V) Space: O(V + E)