How to identify the problem based on 0-1 BFS Algorithm?

The problems based on 0-1 BFS Algorithm have one of the following patterns:

  • All the edges in the graph have weights either 0 or w, where w is not equal to 0
  • We have choices to make, where some choices have cost equal to 0, whereas the other choices have cost w, where w is not equal to 0, and we have to minimize the cost while performing these choices.

The following example would help us understand the concept of identification with the help of some problems:

Problem 1: Given a directed graph and a vertex_source node and destination node, we need to find how many edges we need to reverse in order to make at least 1 path from the vertex_source node to the destination node.

Solution 1: In the above problem, we can assign a weight of zero to all the original edges and for each of the original edges, we create a reversed edge with a weight of one. Now, the problem is reduced to find the path with smallest distance to a node where all the edges have weights either 0 or 1.

Problem 2: Given a matrix of size N X M, such that each cell has a number written on it. From one cell, we can move to any of the adjacent cells which share an edge with the current cell. If the neighboring cell has the same number as the original cell, then the move will cost us 0 coins, else the move will cost us W coins. Find the minimum number of coins required to move from cell (0,0) to cell (N-1, M-1).

Solution 2: In the above problem, we can start a bfs from (0,0) and start checking the neighboring cells. If the neighboring cell has same value, then push it at the front of the deque else push it at the back. We also need to keep a cost[][] array to store the minimum cost to reach a cell.

Problem 3: Given a matrix of size N * M, having some empty cells and some blocked cells. Now, at any cell if we continue to move in the same direction as we moved in the previous cell, then the cost is 0, else if we rotate by 90 degree we incur a cost of C coins. Initially, we are standing at cell (0, 0) and we can choose a direction (Up, Down, Left, Right) and start moving in that direction without any cost. At any time, we can either choose to move in the same direction (if the next cell is empty), else we can choose to rotate by 90 degrees. Find the minimum cost to reach cell (N-1, M-1).

Solution 3: We can check for all the directions as starting direction. Whenever, we are standing at any cell, we can make any of these four choices:

  • Move in the same direction as we moved in the previous cell, hence cost = 0.
  • Turn left, hence cost = C
  • Turn right, hence cost = C
  • Turn in the opposite direction (same as turning left or right twice), but this move is of no benefit to us because we are simply moving back one cell with a cost of 2 * C. So, we don’t move in opposite direction.

Now, if we move in the same direction, we push the new cell to the front of the deque else we push it at the back of the deque. We also need to keep a cost[][] array to store the minimum cost to reach a cell.

0-1 BFS Algorithm for Competitive Programming

0-1 BFS Algorithm is a variation of simple BFS and is used to calculate Single vertex_source Shortest Path to all the nodes in a weighted graph provided the edges have weights 0 and 1 only. This algorithm runs in O(|E|) time which is much faster as compared to the Single Source Shortest Path Algorithms.

Similar Reads

Why to use 0-1 BFS Algorithm?

Using a simple BFS, we can find the minimum distance from a vertex_source node to all other nodes in O(|E|) time provided the graph is an unweighted graph or all the edges have the same weight. In case, the edges have different weights, then we can find the minimum distance to all nodes using Dijkstra’s Algorithm, Bellman-Ford or Shortest Path Faster Algorithm. But, if there is a constraint on the edge weights that they can only be 0 or 1, then applying the above-mentioned algorithms would be an overkill as Dijkstra’s Algorithm runs in O(|E| * log|V|) time and Bellman Ford and SPFA runs in O(|V| * |E|). So, if a graph has edges with weights 0 and 1 only, then we can calculate the minimum distance from a vertex_source node to all the other nodes in O(|E|) time using the 0-1 BFS Algorithm....

Idea behind 0-1 BFS Algorithm:

The idea of 0-1 BFS is similar to Dijkstra’s Algorithm. In the Dijkstra’s Algorithm, we maintain a priority queue or a Min Heap to keep track of all the nodes which can be relaxed in future to get the minimum distance. Initially, we push the vertex_source node with its distance as 0 and then pop it and push all its neighbors who can be relaxed in the future. We keep on doing the same till there is no node to relax further....

How to identify the problem based on 0-1 BFS Algorithm?

The problems based on 0-1 BFS Algorithm have one of the following patterns:...

Implementation of 0-1 BFS Algorithm:

C++ #include using namespace std; // Method to implement 0-1 BFS Algorithm void bfs_01(vector > >& graph, vector& dist, int vertex_source) { // Initializing the distance of vertex_source node // from itself as 0 dist[vertex_source] = 0; deque dq; dq.push_front(vertex_source); while (!dq.empty()) { int node = dq.front(); dq.pop_front(); // Checking all the neighbors for relaxation for (auto edge : graph[node]) { int childNode = edge.first; int weight = edge.second; // If the neighbor can be relaxed if (dist[childNode] > dist[node] + weight) { dist[childNode] = dist[node] + weight; // If the edge weight is 1, // push it at the back of deque if (weight) dq.push_back(childNode); // If the edge weight is 0, // push it at the front of deque else dq.push_front(childNode); } } } } int main() { // Inputs int V = 6, E = 7, vertex_source = 0; vector > > graph(V); vector > edges{ { 0, 1, 1 }, { 1, 2, 1 }, { 2, 3, 1 }, { 3, 4, 1 }, { 4, 5, 0 }, { 5, 0, 0 }, { 1, 4, 1 } }; // Representing the graph as adjacent list for (auto edge : edges) { graph[edge[0]].push_back({ edge[1], edge[2] }); graph[edge[1]].push_back({ edge[0], edge[2] }); } // dist array to store distance of all nodes // from vertex_source node vector dist(V, 1e9); bfs_01(graph, dist, vertex_source); for (int i = 0; i < V; i++) cout << dist[i] << " "; return 0; } Java import java.util.ArrayDeque; import java.util.Deque; import java.util.LinkedList; import java.util.List; public class ZeroOneBFS { // Method to implement 0-1 BFS Algorithm static void bfs01(List> graph, int[] dist, int vertex_source) { // Initializing the distance of the vertex_source node // from itself as 0 dist[vertex_source] = 0; Deque deque = new LinkedList<>(); deque.addFirst(vertex_source); while (!deque.isEmpty()) { int node = deque.pollFirst(); // Checking all the neighbors for relaxation for (Pair edge : graph.get(node)) { int childNode = edge.first; int weight = edge.second; // If the neighbor can be relaxed if (dist[childNode] > dist[node] + weight) { dist[childNode] = dist[node] + weight; // If the edge weight is 1, // push it at the back of the deque if (weight == 1) deque.addLast(childNode); // If the edge weight is 0, // push it at the front of the deque else deque.addFirst(childNode); } } } } public static void main(String[] args) { // Inputs int V = 6, E = 7, vertex_source = 0; List> graph = new LinkedList<>(); List edges = List.of(new int[]{0, 1, 1}, new int[]{1, 2, 1}, new int[]{2, 3, 1}, new int[]{3, 4, 1}, new int[]{4, 5, 0}, new int[]{5, 0, 0}, new int[]{1, 4, 1}); // Representing the graph as an adjacency list for (int i = 0; i < V; i++) { graph.add(new LinkedList<>()); } for (int[] edge : edges) { graph.get(edge[0]).add(new Pair(edge[1], edge[2])); graph.get(edge[1]).add(new Pair(edge[0], edge[2])); } // dist array to store the distance of all nodes // from the vertex_source node int[] dist = new int[V]; for (int i = 0; i < V; i++) { dist[i] = (int) 1e9; } bfs01(graph, dist, vertex_source); for (int i = 0; i < V; i++) { System.out.print(dist[i] + " "); } } static class Pair { int first, second; Pair(int first, int second) { this.first = first; this.second = second; } } } // This code is contributed by rambabuguphka Python3 from collections import deque # Method to implement 0-1 BFS Algorithm def bfs_01(graph, dist, vertex_source): # Initializing the distance of vertex_source node # from itself as 0 dist[vertex_source] = 0 dq = deque() dq.appendleft(vertex_source) while dq: node = dq.popleft() # Checking all the neighbors for relaxation for edge in graph[node]: childNode, weight = edge # If the neighbor can be relaxed if dist[childNode] > dist[node] + weight: dist[childNode] = dist[node] + weight # If the edge weight is 1, # push it at the back of deque if weight: dq.append(childNode) # If the edge weight is 0, # push it at the front of deque else: dq.appendleft(childNode) # Inputs V = 6 E = 7 vertex_source = 0 graph = [[] for _ in range(V)] edges = [[0, 1, 1], [1, 2, 1], [2, 3, 1], [3, 4, 1], [4, 5, 0], [5, 0, 0], [1, 4, 1]] # Representing the graph as adjacent list for edge in edges: graph[edge[0]].append((edge[1], edge[2])) graph[edge[1]].append((edge[0], edge[2])) # dist array to store distance of all nodes # from vertex_source node dist = [float('inf')] * V bfs_01(graph, dist, vertex_source) for i in range(V): print(dist[i], end=" ") C# using System; using System.Collections.Generic; public class ZeroOneBFS { // Method to implement 0-1 BFS Algorithm static void BFS01(List> graph, int[] dist, int vertex_source) { // Initializing the distance of the vertex_source node // from itself as 0 dist[vertex_source] = 0; LinkedList deque = new LinkedList(); deque.AddLast(vertex_source); while (deque.Count > 0) { int node = deque.First.Value; deque.RemoveFirst(); // Checking all the neighbors for relaxation foreach (Pair edge in graph[node]) { int childNode = edge.first; int weight = edge.second; // If the neighbor can be relaxed if (dist[childNode] > dist[node] + weight) { dist[childNode] = dist[node] + weight; // If the edge weight is 1, // push it at the back of the deque if (weight == 1) deque.AddLast(childNode); // If the edge weight is 0, // push it at the front of the deque else deque.AddFirst(childNode); } } } } public static void Main(string[] args) { // Inputs int V = 6, vertex_source = 0; List> graph = new List>(); List edges = new List { new int[] {0, 1, 1}, new int[] {1, 2, 1}, new int[] {2, 3, 1}, new int[] {3, 4, 1}, new int[] {4, 5, 0}, new int[] {5, 0, 0}, new int[] {1, 4, 1} }; // Representing the graph as an adjacency list for (int i = 0; i < V; i++) { graph.Add(new List()); } foreach (int[] edge in edges) { graph[edge[0]].Add(new Pair(edge[1], edge[2])); graph[edge[1]].Add(new Pair(edge[0], edge[2])); } // dist array to store the distance of all nodes // from the vertex_source node int[] dist = new int[V]; for (int i = 0; i < V; i++) { dist[i] = int.MaxValue; } BFS01(graph, dist, vertex_source); for (int i = 0; i < V; i++) { Console.Write(dist[i] + " "); } } public class Pair { public int first, second; public Pair(int first, int second) { this.first = first; this.second = second; } } } Javascript // Method to implement 0-1 BFS Algorithm function bfs_01(graph, dist, vertex_source) { // Initializing the distance of vertex_source node // from itself as 0 dist[vertex_source] = 0; let dq = []; dq.push(vertex_source); while (dq.length > 0) { let node = dq.shift(); // Checking all the neighbors for relaxation for (let edge of graph[node]) { let childNode = edge[0]; let weight = edge[1]; if (dist[childNode] > dist[node] + weight) { dist[childNode] = dist[node] + weight; // If the edge weight is 1, // push it at the back of deque if (weight) { dq.push(childNode); } // If the edge weight is 0, // push it at the front of deque else { dq.unshift(childNode); } } } } } // Inputs let V = 6, E = 7, vertex_source = 0; let graph = Array.from({ length: V }, () => []); // Representing the graph as adjacent list let edges = [ [0, 1, 1], [1, 2, 1], [2, 3, 1], [3, 4, 1], [4, 5, 0], [5, 0, 0], [1, 4, 1] ]; for (let edge of edges) { graph[edge[0]].push([edge[1], edge[2]]); graph[edge[1]].push([edge[0], edge[2]]); } // dist array to store distance of all nodes // from vertex_source node let dist = Array(V).fill(1e9); bfs_01(graph, dist, vertex_source); for (let i = 0; i < V; i++) { process.stdout.write(dist[i] + " "); }...

Use case of 0-1 BFS Algorithm in Competitive Programming:

1. Minimum edges to reverse to make path from a source to a destination:...

Dial’s Algorithm:

We can also extend 0-1 BFS Algorithm for a graph having multiple weights until all the edge weights are less than W, where W is a small integer. We can maintain K buckets in the queue and start popping from the front of the queue. This way, we start moving from smaller weight buckets to larger weight buckets....

Practice Problems on 0-1 BFS Algorithm for Competitive Programming:

Problem Problem Link Minimum Cost to reach the end of the matrix Practice Now Minimize the number of turns needed to reach from top left cell to bottom right cell of the matrix Practice Now Count of Reachable cells in Grid within given Left-Right moves Practice Now Two Rats in a Maze Practice Now Minimum Jumps to move outside the matrix Practice Now...