DSA sheet / Graph

Message Route

easy about 20 min BFS / DFSbfsshortest-pathpath-reconstruction
Open on CSES

Do these first: Counting Rooms

The problem in brief

A network has n computers (up to 100 000) and m two-way connections (up to 200 000). Print the fewest computers a message needs to pass through going from computer 1 to computer n, followed by one such route. If no route exists, print IMPOSSIBLE.

Try it

Tab indents; press Esc, then Tab, to leave the box. Ctrl+Enter runs.

Hints

Stuck? Reveal one hint at a time. Each nudges without giving away the next.

The walkthrough

Spoilers ahead: open a section only after you have given the hints a fair try.

How to think

Same principle as the grid maze, on a general graph: BFS from the source visits nodes in non-decreasing distance, so the first time it reaches a node it has found a shortest path to it. Then a parent array turns the distances into an actual route: parent[v] is the node from which v was first discovered, and following parents from n leads back to 1 along a shortest path.

The number to print counts computers on the route, which is edges plus one. If BFS ends without ever discovering n, there is no route. The habit: BFS plus parent pointers is your default answer to “shortest path, unit weights, and print the path”. Adjacency lists (not a matrix) keep memory and time linear in the number of edges.

Intuition

Send a message out from computer 1 to all its neighbours, then from those to their neighbours, and so on, wave by wave. The first wave to touch computer n is the shortest route; each computer remembers who told it about the message.

Approach
  1. Build adjacency lists from the m connections (both directions).
  2. BFS from 1, recording parent[v] when first discovering v.
  3. If n was not discovered print IMPOSSIBLE.
  4. Otherwise follow parent from n to 1, reverse the list, print its length and the computers.

Pitfalls: n = 1 is not possible here (the endpoints differ) but handle a generic graph anyway; do not add duplicates to the queue (mark as discovered when pushing); use fast I/O for up to 2 * 10^5 edges.

Complexity

O(n + m) time and memory.

Solutions

Written from scratch and checked by compiling and running each one against a brute force on random inputs. Fast input/output, the way you would submit it.

Show solutions (C++17, Python 3, Java 17, Node.js)
#include <bits/stdc++.h>
using namespace std;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int n, m;
    cin >> n >> m;
    vector<vector<int>> adj(n + 1);
    for (int i = 0; i < m; i++) {
        int a, b;
        cin >> a >> b;
        adj[a].push_back(b);
        adj[b].push_back(a);
    }
    vector<int> parent(n + 1, 0);
    vector<int> queue;
    queue.reserve(n);
    parent[1] = -1;
    queue.push_back(1);
    for (size_t head = 0; head < queue.size() && parent[n] == 0; head++) {
        int u = queue[head];
        for (int v : adj[u]) {
            if (parent[v] == 0) {
                parent[v] = u;
                queue.push_back(v);
            }
        }
    }
    if (parent[n] == 0) {
        cout << "IMPOSSIBLE\n";
        return 0;
    }
    vector<int> path;
    for (int v = n; v != -1; v = parent[v]) path.push_back(v);
    reverse(path.begin(), path.end());
    cout << path.size() << "\n";
    for (size_t i = 0; i < path.size(); i++) cout << path[i] << (i + 1 < path.size() ? ' ' : '\n');
    return 0;
}

Problem: CSES Problem Set (Antti Laaksonen, University of Helsinki), CC BY-NC-SA 4.0. The explanations and code above are original (© Anupam Kumar).

Related problems

Back to the sheet