BFS with Parity States¶
In one sentence
Breadth-first search visits vertices in order of distance; if the question is about walks of an exact length, search over states (vertex, number of steps is even/odd) instead of plain vertices.
1. What problem does it solve?¶
Example — AIO 2019 · Evading Capture (AIO 2019 Q5, lesson of 22 August)
There are \(N\) cities and \(E\) undirected roads. You start in city \(X\) and must make exactly \(K\) hops, each to a neighbouring city (you may revisit cities and roads). In how many different cities could you finish?
Limits: \(N, E \le 10^5\), \(K \le 10^9\). It is guaranteed that at least one sequence of \(K\) hops exists.
Input Output
6 5 4 2
3 1
3 2
1 2
4 2
3 6 3
From city 4 the two-hop walks are \(4 \to 2 \to 1\), \(4 \to 2 \to 3\) and \(4 \to 2 \to 4\).
The naive way. Keep the set of cities reachable after \(1, 2, \dots, K\) hops. Each step costs \(O(N + E)\), and \(K\) can be \(10^9\).
The observation. Once you can stand in a city \(v\) after \(d\) hops, you can also stand there after \(d + 2\), \(d + 4\), … hops: walk to a neighbour and straight back. So only two things matter for \(v\): the fewest even number of hops that reaches it and the fewest odd number.
2. The math¶
2.1 BFS in one paragraph¶
BFS starts from the source with distance \(0\) and uses a queue. It pops the front state \(u\) and gives every not-yet-seen neighbour distance \(d(u) + 1\), pushing it to the back. Because the queue always holds states in non-decreasing distance order, the first time a state is reached is along a shortest route. Every state is pushed once and every edge is looked at a constant number of times: \(O(N + E)\).
2.2 The state graph¶
Make two copies of every city: \((v, 0)\) = "at \(v\) after an even number of hops" and \((v, 1)\) = "after an odd number". A road \(u - v\) connects \((u, 0)\) with \((v, 1)\) and \((u, 1)\) with \((v, 0)\), since every hop flips the parity. BFS from \((X, 0)\) gives
2.3 The answer¶
City \(v\) can be the finish exactly when \(\texttt{dist}[v][K \bmod 2] \le K\).
- Necessary: a walk of exactly \(K\) hops ending at \(v\) has parity \(K \bmod 2\), so the shortest such walk is at most \(K\).
- Sufficient: take the shortest walk of the right parity, length \(d \le K\). The spare \(K - d\) hops are an even number; burn them by bouncing along one road next to \(v\). Such a road exists: if \(d > 0\) we arrived at \(v\) along one; if \(d = 0\) then \(v = X\), and since some \(K \ge 1\) hop walk exists, \(X\) has a neighbour.
2.4 Trace on sample 1¶
Neighbours: \(1:\{3,2\}\), \(2:\{3,1,4\}\), \(3:\{1,2,6\}\), \(4:\{2\}\), \(6:\{3\}\), \(5:\{\}\). BFS from \((4, 0)\):
A state \((u, p)\) sends each neighbour \(v\) to \((v, 1 - p)\).
| pop | distance of popped | new states |
|---|---|---|
| (4,0) | 0 | (2,1) |
| (2,1) | 1 | (3,0), (1,0) |
| (3,0) | 2 | (1,1), (6,1) |
| (1,0) | 2 | (3,1) |
| (1,1) | 3 | (2,0) |
| (6,1) | 3 | — |
| (3,1) | 3 | (6,0) |
| (2,0) | 4 | (4,1) |
| (6,0), (4,1) | 4, 5 | — |
| city \(v\) | 1 | 2 | 3 | 4 | 5 | 6 |
|---|---|---|---|---|---|---|
dist[v][0] (even) |
2 | 4 | 2 | 0 | ∞ | 4 |
dist[v][1] (odd) |
3 | 1 | 3 | 5 | ∞ | 3 |
\(K = 2\) is even, so count cities with an even distance \(\le 2\): cities \(1\) (2), \(3\) (2) and \(4\) (0). Answer 3.
3. The code from class (22 August)¶
This is the program we wrote together. dist[u][p] is the BFS distance of state \((u, p)\), and the comments are our thinking at the board. It passes all three official samples.
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
int main() {
int n, e, x, k;
cin >> n >> e >> x >> k;
vector<vector<int> > adj(n + 1);
for (int i = 0; i < e; i++) {
int u, v;
cin >> u >> v;
adj[u].push_back(v);
adj[v].push_back(u);
}
vector<vector<int> > dist(n + 1, vector<int>(2,INT_MAX));
dist[x][0] = 0;
queue<pair<int, int> > q;
q.push({x, 0});
while (!q.empty()) {
int u = q.front().first;
int p = q.front().second;
q.pop();
for (auto v: adj[u]) {
if (dist[v][p ^ 1] == INT_MAX) {
dist[v][p ^ 1] = dist[u][p] + 1;
q.push({v, p ^ 1});
}
}
}
// if dist[i] > k ?
// no matter how we move, we can't go to vertex i
// if dist[i] < k
// if dist[i]%2 == k%2
// then it's good
// if dist[i]%2 != k%2
int p = k % 2;
int ans = 0;
for (int u = 1; u <= n; u++) {
if (dist[u][p] <= k) {
ans++;
}
}
cout << ans << endl;
return 0;
}
p ^ 1 flips \(0 \leftrightarrow 1\), which is exactly "one more hop changes the parity". Unreached states keep INT_MAX, which is larger than any \(K \le 10^9\), so they are never counted.
4. The general pattern: state = vertex × extra information¶
Parity is the simplest "extra information". The same trick answers many other questions: add whatever you need to remember to the state and run BFS on the bigger graph.
| Extra information | State | Number of states |
|---|---|---|
| parity of the number of steps | \((v, p)\), \(p \in \{0,1\}\) | \(2N\) |
| steps modulo \(m\) | \((v, s \bmod m)\) | \(mN\) |
| "have I used my one teleport yet?" | \((v, \text{used})\) | \(2N\) |
| which keys I carry (few keys) | \((v, \text{mask})\) | \(2^k N\) (see bitmasks) |
5. Common mistakes¶
Marking visited per vertex instead of per state
If visited[v] is shared by both parities, reaching \(v\) at an odd distance blocks the even one. Every state needs its own entry.
Simulating \(K\) steps
\(K\) is up to \(10^9\). Any loop over the number of hops is too slow; the parity argument replaces it.
Forgetting the start state
Set dist[x][0] = 0 and push it before the loop. City \(X\) itself counts when \(K\) is even.
Queue of vertices only
Push the pair (v, parity), not just v, otherwise you do not know which copy you popped.
6. Practice¶
| Problem | Where | Idea |
|---|---|---|
| AIO 2019 · Evading Capture | AIO 2019 Q5 | this page |
| AIO 2025 · Robot Writing | AIO 2025 Q6 | the same "distance fits and parity matches" test, on a line |
| CSES · Labyrinth | CSES | plain BFS on a grid, recover the path |
| CSES · Message Route | CSES | plain BFS shortest path in a graph |
Credits & licenses
- §3 is the program written in class on 22 August, unchanged. Sample data is from the official AIO 2019 statement on ORAC.
- The BFS summary, state-graph argument, proof of the answer, trace, table and mistakes are ours.