0-1 BFS (Shortest Path in a Binary Weight Graph)
Given an undirected graph where every edge has a weight as either 0 or 1. The task is to find the shortest path from the source vertex to all other vertices in the graph.
Example:
Input: Source Vertex = 0 and below graph Having vertices like (u, v, w):
edges: [[0,1,0], [0, 7, 1], [1,2,1], [1, 7, 1], [2, 3, 0], [2, 5, 0], [2, 8, 1], [3, 4, 1],[3, 5, 1],[4, 5, 1],[5, 6, 1],[6, 7, 1],[7, 8, 1]]Output: 0 0 1 1 2 1 2 1 2
[Naive Approach] Using Dijkstra Algorithm - O(E * log (V)) Time and O(V) Space
In Dijkstra's Algorithm, the goal is to find the shortest distance from a given source node to all other nodes in the graph. As the source node is the starting point, its distance is initialized to zero. From there, we iteratively pick the unprocessed node with the minimum distance from the source, this is where a min-heap (priority queue) or a set is typically used for efficiency.
Refer to Dijkstra's Algorithm to find Shortest Path for detailed explanation.
[Expected Approach] Using Deque - O(V + E) time and O(V + E) space
The idea is to adapt BFS to efficiently handle graphs with binary weights (0 or 1) by using a deque instead of a queue. When we encounter an edge with weight 0, we add its destination to the front of the deque because it doesn't increase the distance. When we encounter an edge with weight 1, we add its destination to the back of the deque because it increases the distance by one unit.
Step by step approach:
- Initialize distances array with infinity for all vertices except source.
- Use a deque to process vertices in order of increasing distance.
- For each vertex, examine all adjacent vertices. If the new distance of vertex is less than current distance, then
- If edge weight is 0, add adjacent vertex to front of deque (priority).
- If edge weight is 1, add adjacent vertex to back of deque.
How it works?
The key property of the 0-1 BFS algorithm is that the deque maintains nodes in a very specific order. At any point during execution, the deque contains vertices with at most two consecutive distance values (d and d+1).
The deque will have a structure like [d, d, d, d, d+1, d+1, d+1], where all vertices with distance d appear before any vertex with distance d+1. This property is maintained because:
- When we encounter an edge with weight 0, we add the destination to the front of the deque (maintaining distance d)
- When we encounter an edge with weight 1, we add the destination to the back of the deque (creating distance d+1)
This ordering ensures that we process all vertices with distance d before processing any vertex with distance d+1. Furthermore, nodes with distance d+2 can only be added after all nodes with distance d have been processed (because they can only be reached through nodes with distance d+1).
// C++ program to implement 0-1 BFS
// (Shortest Path in a Binary Weight Graph)
#include <bits/stdc++.h>
using namespace std;
vector<int> minDist(int n, int src, vector<vector<int>> &edges) {
// Create adjacency list representation of the graph
vector<vector<vector<int>>> adj(n);
for (auto &edge : edges) {
int u = edge[0];
int v = edge[1];
int w = edge[2];
adj[u].push_back({v, w});
adj[v].push_back({u, w});
}
// Initialize distances to infinity
vector<int> dist(n, INT_MAX);
dist[src] = 0;
// Use deque for 0-1 BFS
deque<int> dq;
dq.push_back(src);
while (!dq.empty()) {
int u = dq.front();
dq.pop_front();
// Process all adjacent vertices
for (auto &edge : adj[u]) {
int v = edge[0];
int weight = edge[1];
// If we can improve the distance
if (dist[u] + weight < dist[v]) {
dist[v] = dist[u] + weight;
// If weight is 0, push to front (higher priority)
// If weight is 1, push to back (lower priority)
if (weight == 0)
dq.push_front(v);
else
dq.push_back(v);
}
}
}
return dist;
}
int main() {
int n = 9, src = 0;
vector<vector<int>> edges = {
{0, 1, 0}, {0, 7, 1}, {1, 2, 1}, {1, 7, 1},
{2, 3, 0}, {2, 5, 0}, {2, 8, 1}, {3, 4, 1}, {3, 5, 1},
{4, 5, 1}, {5, 6, 1}, {6, 7, 1}, {7, 8, 1}
};
vector<int> res = minDist(n, src, edges);
for (int i = 0; i < n; i++) {
cout << res[i] << " ";
}
cout << endl;
return 0;
}
// Java program to implement 0-1 BFS
// (Shortest Path in a Binary Weight Graph)
import java.util.ArrayDeque;
import java.util.Deque;
class GfG {
static int[] minDist(int n, int src, int[][] edges) {
// Create adjacency list representation of the graph
int[][][] adj = new int[n][][];
int[] edgeCount = new int[n];
// First pass to count edges per node
for (int[] edge : edges) {
int u = edge[0];
int v = edge[1];
edgeCount[u]++;
edgeCount[v]++;
}
// Initialize adjacency lists
for (int i = 0; i < n; i++) {
adj[i] = new int[edgeCount[i]][2];
edgeCount[i] = 0; // Reset to use as index
}
// Populate adjacency lists
for (int[] edge : edges) {
int u = edge[0];
int v = edge[1];
int w = edge[2];
adj[u][edgeCount[u]++] = new int[]{v, w};
adj[v][edgeCount[v]++] = new int[]{u, w};
}
// Initialize distances to infinity
int[] dist = new int[n];
for (int i = 0; i < n; i++) {
dist[i] = Integer.MAX_VALUE;
}
dist[src] = 0;
// Use deque for 0-1 BFS
Deque<Integer> dq = new ArrayDeque<>();
dq.addLast(src);
while (!dq.isEmpty()) {
int u = dq.removeFirst();
// Process all adjacent vertices
for (int[] edge : adj[u]) {
int v = edge[0];
int weight = edge[1];
// If we can improve the distance
if (dist[u] + weight < dist[v]) {
dist[v] = dist[u] + weight;
// If weight is 0, push to front (higher priority)
// If weight is 1, push to back (lower priority)
if (weight == 0)
dq.addFirst(v);
else
dq.addLast(v);
}
}
}
return dist;
}
public static void main(String[] args) {
int n = 9, src = 0;
int[][] edges = {
{0, 1, 0}, {0, 7, 1}, {1, 2, 1}, {1, 7, 1},
{2, 3, 0}, {2, 5, 0}, {2, 8, 1}, {3, 4, 1}, {3, 5, 1},
{4, 5, 1}, {5, 6, 1}, {6, 7, 1}, {7, 8, 1}
};
int[] res = minDist(n, src, edges);
for (int i = 0; i < n; i++) {
System.out.print(res[i] + " ");
}
System.out.println();
}
}
# Python program to implement 0-1 BFS
# (Shortest Path in a Binary Weight Graph)
from collections import deque
def minDist(n, src, edges):
# Create adjacency list representation of the graph
adj = [[] for _ in range(n)]
for edge in edges:
u = edge[0]
v = edge[1]
w = edge[2]
adj[u].append((v, w))
adj[v].append((u, w))
# Initialize distances to infinity
dist = [float('inf')] * n
dist[src] = 0
# Use deque for 0-1 BFS
dq = deque()
dq.append(src)
while dq:
u = dq.popleft()
# Process all adjacent vertices
for edge in adj[u]:
v = edge[0]
weight = edge[1]
# If we can improve the distance
if dist[u] + weight < dist[v]:
dist[v] = dist[u] + weight
# If weight is 0, push to front (higher priority)
# If weight is 1, push to back (lower priority)
if weight == 0:
dq.appendleft(v)
else:
dq.append(v)
return dist
if __name__ == "__main__":
n = 9
src = 0
edges = [
[0, 1, 0], [0, 7, 1], [1, 2, 1], [1, 7, 1],
[2, 3, 0], [2, 5, 0], [2, 8, 1], [3, 4, 1], [3, 5, 1],
[4, 5, 1], [5, 6, 1], [6, 7, 1], [7, 8, 1]
]
res = minDist(n, src, edges)
for val in res:
print(val, end=" ")
print()
// C# program to implement 0-1 BFS
// (Shortest Path in a Binary Weight Graph)
using System;
using System.Collections.Generic;
class GfG {
static int[] MinDist(int n, int src, int[][] edges) {
// Create adjacency list representation of the graph
List<Tuple<int, int>>[] adj = new List<Tuple<int, int>>[n];
for (int i = 0; i < n; i++) {
adj[i] = new List<Tuple<int, int>>();
}
foreach (var edge in edges) {
int u = edge[0];
int v = edge[1];
int w = edge[2];
adj[u].Add(Tuple.Create(v, w));
adj[v].Add(Tuple.Create(u, w));
}
// Initialize distances to infinity
int[] dist = new int[n];
for (int i = 0; i < n; i++) {
dist[i] = int.MaxValue;
}
dist[src] = 0;
// Use deque for 0-1 BFS
LinkedList<int> dq = new LinkedList<int>();
dq.AddLast(src);
while (dq.Count > 0) {
int u = dq.First.Value;
dq.RemoveFirst();
// Process all adjacent vertices
foreach (var edge in adj[u]) {
int v = edge.Item1;
int weight = edge.Item2;
// If we can improve the distance
if (dist[u] + weight < dist[v]) {
dist[v] = dist[u] + weight;
// If weight is 0, push to front (higher priority)
// If weight is 1, push to back (lower priority)
if (weight == 0)
dq.AddFirst(v);
else
dq.AddLast(v);
}
}
}
return dist;
}
static void Main() {
int n = 9, src = 0;
int[][] edges = new int[][] {
new int[] {0, 1, 0}, new int[] {0, 7, 1},
new int[] {1, 2, 1}, new int[] {1, 7, 1},
new int[] {2, 3, 0}, new int[] {2, 5, 0},
new int[] {2, 8, 1}, new int[] {3, 4, 1},
new int[] {3, 5, 1}, new int[] {4, 5, 1},
new int[] {5, 6, 1}, new int[] {6, 7, 1},
new int[] {7, 8, 1}
};
int[] res = MinDist(n, src, edges);
foreach (int val in res) {
Console.Write(val + " ");
}
Console.WriteLine();
}
}
// JavaScript program to implement 0-1 BFS
// (Shortest Path in a Binary Weight Graph)
function minDist(n, src, edges) {
// Create adjacency list representation of the graph
let adj = Array.from({length: n}, () => []);
for (let edge of edges) {
let u = edge[0];
let v = edge[1];
let w = edge[2];
adj[u].push([v, w]);
adj[v].push([u, w]);
}
// Initialize distances to infinity
let dist = new Array(n).fill(Infinity);
dist[src] = 0;
// Use deque for 0-1 BFS
let dq = [];
dq.push(src);
while (dq.length > 0) {
let u = dq.shift();
// Process all adjacent vertices
for (let edge of adj[u]) {
let v = edge[0];
let weight = edge[1];
// If we can improve the distance
if (dist[u] + weight < dist[v]) {
dist[v] = dist[u] + weight;
// If weight is 0, push to front (higher priority)
// If weight is 1, push to back (lower priority)
if (weight === 0)
dq.unshift(v);
else
dq.push(v);
}
}
}
return dist;
}
let n = 9, src = 0;
let edges = [
[0, 1, 0], [0, 7, 1], [1, 2, 1], [1, 7, 1],
[2, 3, 0], [2, 5, 0], [2, 8, 1], [3, 4, 1], [3, 5, 1],
[4, 5, 1], [5, 6, 1], [6, 7, 1], [7, 8, 1]
];
let res = minDist(n, src, edges);
console.log(res.join(' '));
Output
0 0 1 1 2 1 2 1 2