Shortest Path with Dijkstra

Problem

An undirected graph has n nodes (numbered 1 to n) and m weighted edges. The first line has n and m. The next m lines have u v w (an edge between u and v with the positive weight w). The last line has two nodes: the start s and the target t. Print the length of the shortest path from s to t, or -1 if t can not be reached.

Constraints

  • 1 <= n <= 1000
  • 0 <= m <= 5000
  • 1 <= w <= 10^6

Examples

Input

4 4
1 2 1
2 3 2
1 3 5
3 4 1
1 4

Output

4

Solutions

Best approachTime O((n + m) log n)Space O(n + m)

Dijkstra's algorithm always finalizes the closest unfinished node. When all weights are positive, no later path can make that node closer. A priority queue finds the closest node quickly. The JavaScript and TypeScript versions sort a small list instead, which is simpler but slower for big graphs.

Same code works in Java810172125Basic features only, so nothing changes between versions.
/*
 * Problem : Shortest path length.
 * Input   : Graph edges, then s and t.
 * Output  : The distance or -1.
 * Approach: Priority queue.
 * Time    : O((n + m) log n)
 * Space   : O(n + m)
 * Java    : 8 or newer.
 */
import java.util.Scanner;

public class Main {
    // This method solves the task. It receives the input and returns the answer.
    static long solve(String[] lines) {
        String[] header = lines[0].split(" ");
        int n = Integer.parseInt(header[0]);
        int m = Integer.parseInt(header[1]);

        // Step 1: Adjacency lists. For each node we keep its neighbours as {neighbour, weight}.
        java.util.List<java.util.List<int[]>> graph = new java.util.ArrayList<>();
        for (int i = 0; i <= n; i++) {
            graph.add(new java.util.ArrayList<>());
        }
        for (int i = 1; i <= m; i++) {
            String[] edge = lines[i].split(" ");
            int u = Integer.parseInt(edge[0]);
            int v = Integer.parseInt(edge[1]);
            int w = Integer.parseInt(edge[2]);
            graph.get(u).add(new int[] {v, w});
            graph.get(v).add(new int[] {u, w});
        }
        String[] ends = lines[m + 1].split(" ");
        int start = Integer.parseInt(ends[0]);
        int target = Integer.parseInt(ends[1]);

        // Step 2: distance[x] = the best known distance from the start. At first all are "infinite".
        long[] distance = new long[n + 1];
        java.util.Arrays.fill(distance, Long.MAX_VALUE);
        distance[start] = 0;

        // Step 3: A priority queue always gives the node with the smallest known distance.
        java.util.PriorityQueue<long[]> queue = new java.util.PriorityQueue<>((x, y) -> Long.compare(x[0], y[0]));
        queue.add(new long[] {0, start});

        while (!queue.isEmpty()) {
            long[] top = queue.poll();
            int node = (int) top[1];

            // Step 4: Skip old entries. A shorter distance for this node was already found.
            if (top[0] > distance[node]) {
                continue;
            }

            // Step 5: Relax the edges. If we find a shorter way to a neighbour, we save it and add the neighbour to the queue.
            for (int[] edge : graph.get(node)) {
                long candidate = top[0] + edge[1];
                if (candidate < distance[edge[0]]) {
                    distance[edge[0]] = candidate;
                    queue.add(new long[] {candidate, edge[0]});
                }
            }
        }
        return distance[target] == Long.MAX_VALUE ? -1 : distance[target];
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        java.util.List<String> all = new java.util.ArrayList<>();
        while (scanner.hasNextLine()) {
            String line = scanner.nextLine().trim();
            if (!line.isEmpty()) {
                all.add(line);
            }
        }
        String[] lines = all.toArray(new String[0]);
        System.out.println(solve(lines));
    }
}
Hints (2)
  1. Why does Dijkstra need positive weights?
  2. What does the priority queue return?