Create zero_one_bfs.java (#6560)

* Create zero_one_bfs.java

* Rename zero_one_bfs.java to ZeroOneBfs.java

* Update ZeroOneBfs.java

* Update ZeroOneBfs.java

* Create ZeroOneBfsTest.java

* Update ZeroOneBfsTest.java

---------

Co-authored-by: a <alexanderklmn@gmail.com>
This commit is contained in:
ananya-research
2025-10-06 14:14:32 -04:00
committed by GitHub
parent 9484c7eead
commit 8ca2d9f820
2 changed files with 145 additions and 0 deletions

View File

@@ -0,0 +1,77 @@
package com.thealgorithms.graph;
import java.util.ArrayDeque;
import java.util.Arrays;
import java.util.Deque;
import java.util.List;
/**
* 0-1 BFS for shortest paths on graphs with edges weighted 0 or 1.
*
* <p>Time Complexity: O(V + E). Space Complexity: O(V).
*
* <p>References:
* <ul>
* <li>https://cp-algorithms.com/graph/01_bfs.html</li>
* </ul>
*/
public final class ZeroOneBfs {
private ZeroOneBfs() {
// Utility class; do not instantiate.
}
/**
* Computes shortest distances from {@code src} in a graph whose edges have weight 0 or 1.
*
* @param n the number of vertices, labeled {@code 0..n-1}
* @param adj adjacency list; for each vertex u, {@code adj.get(u)} is a list of pairs
* {@code (v, w)} where {@code v} is a neighbor and {@code w} is 0 or 1
* @param src the source vertex
* @return an array of distances; {@code Integer.MAX_VALUE} denotes unreachable
* @throws IllegalArgumentException if {@code n < 0}, {@code src} is out of range,
* or any edge has weight other than 0 or 1
*/
public static int[] shortestPaths(int n, List<List<int[]>> adj, int src) {
if (n < 0 || src < 0 || src >= n) {
throw new IllegalArgumentException("Invalid n or src");
}
int[] dist = new int[n];
Arrays.fill(dist, Integer.MAX_VALUE);
Deque<Integer> dq = new ArrayDeque<>();
dist[src] = 0;
dq.addFirst(src);
while (!dq.isEmpty()) {
int u = dq.pollFirst();
List<int[]> edges = adj.get(u);
if (edges == null) {
continue;
}
for (int[] e : edges) {
if (e == null || e.length < 2) {
continue;
}
int v = e[0];
int w = e[1];
if (v < 0 || v >= n) {
continue; // ignore bad edges
}
if (w != 0 && w != 1) {
throw new IllegalArgumentException("Edge weight must be 0 or 1");
}
int nd = dist[u] + w;
if (nd < dist[v]) {
dist[v] = nd;
if (w == 0) {
dq.addFirst(v);
} else {
dq.addLast(v);
}
}
}
}
return dist;
}
}

View File

@@ -0,0 +1,68 @@
package com.thealgorithms.graph;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import java.util.ArrayList;
import java.util.List;
import org.junit.jupiter.api.Test;
class ZeroOneBfsTest {
// Helper to build adjacency list with capacity n
private static List<List<int[]>> makeAdj(int n) {
List<List<int[]>> adj = new ArrayList<>(n);
for (int i = 0; i < n; i++) {
adj.add(new ArrayList<>());
}
return adj;
}
@Test
void simpleLineGraph() {
int n = 4;
List<List<int[]>> adj = makeAdj(n);
// 0 --0--> 1 --1--> 2 --0--> 3
adj.get(0).add(new int[] {1, 0});
adj.get(1).add(new int[] {2, 1});
adj.get(2).add(new int[] {3, 0});
int[] dist = ZeroOneBfs.shortestPaths(n, adj, 0);
assertArrayEquals(new int[] {0, 0, 1, 1}, dist);
}
@Test
void parallelEdgesPreferZero() {
int n = 3;
List<List<int[]>> adj = makeAdj(n);
// Two edges 0->1: weight 1 and weight 0. Algorithm should choose 0.
adj.get(0).add(new int[] {1, 1});
adj.get(0).add(new int[] {1, 0});
adj.get(1).add(new int[] {2, 1});
int[] dist = ZeroOneBfs.shortestPaths(n, adj, 0);
assertArrayEquals(new int[] {0, 0, 1}, dist);
}
@Test
void unreachableNodes() {
int n = 3;
List<List<int[]>> adj = makeAdj(n);
adj.get(0).add(new int[] {1, 0});
int[] dist = ZeroOneBfs.shortestPaths(n, adj, 0);
// node 2 unreachable -> Integer.MAX_VALUE
assertArrayEquals(new int[] {0, 0, Integer.MAX_VALUE}, dist);
}
@Test
void invalidArgs() {
int n = 2;
List<List<int[]>> adj = makeAdj(n);
// invalid weight
adj.get(0).add(new int[] {1, 2});
assertThrows(IllegalArgumentException.class, () -> ZeroOneBfs.shortestPaths(n, adj, 0));
// invalid src
assertThrows(IllegalArgumentException.class, () -> ZeroOneBfs.shortestPaths(n, adj, -1));
assertThrows(IllegalArgumentException.class, () -> ZeroOneBfs.shortestPaths(n, adj, 2));
}
}