807-bipartite-check — Bipartite Check
Tutorial Video
Text description (accessibility)
This video demonstrates the "807-bipartite-check — Bipartite Check" functional Rust example. Difficulty level: Advanced. Key concepts covered: Functional Programming. A bipartite graph can be 2-colored: vertices split into two sets where all edges go between sets (no edges within a set). Key difference from OCaml: 1. **BFS queue**: Rust uses `VecDeque<usize>` (FIFO); OCaml uses `Queue.t` — equivalent data structures.
Tutorial
The Problem
A bipartite graph can be 2-colored: vertices split into two sets where all edges go between sets (no edges within a set). BFS-based 2-coloring checks bipartiteness in O(V+E). Applications: job matching (workers and jobs are two sets), recommendation systems (users and items), scheduling (tasks and time slots), and the fundamental theorem that a graph is bipartite if and only if it contains no odd-length cycles.
🎯 Learning Outcomes
Code Example
#![allow(clippy::all)]
//! # Bipartite Check
pub fn is_bipartite(n: usize, edges: &[(usize, usize)]) -> bool {
let mut adj = vec![vec![]; n];
for &(u, v) in edges {
adj[u].push(v);
adj[v].push(u);
}
let mut color = vec![None; n];
fn bfs(start: usize, adj: &[Vec<usize>], color: &mut [Option<bool>]) -> bool {
use std::collections::VecDeque;
let mut q = VecDeque::new();
q.push_back(start);
color[start] = Some(true);
while let Some(u) = q.pop_front() {
for &v in &adj[u] {
if color[v].is_none() {
color[v] = Some(!color[u].unwrap());
q.push_back(v);
} else if color[v] == color[u] {
return false;
}
}
}
true
}
for v in 0..n {
if color[v].is_none() && !bfs(v, &adj, &mut color) {
return false;
}
}
true
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_bipartite() {
assert!(is_bipartite(4, &[(0, 1), (1, 2), (2, 3), (3, 0)]));
}
#[test]
fn test_not_bipartite() {
assert!(!is_bipartite(3, &[(0, 1), (1, 2), (2, 0)]));
}
}Key Differences
VecDeque<usize> (FIFO); OCaml uses Queue.t — equivalent data structures.Option<bool> (uncolored / colored); OCaml uses int option or bool option similarly.for v in 0..n outer loop is identical.OCaml Approach
OCaml implements BFS with Queue.t and a color: bool option array. The Queue.add / Queue.pop pattern drives the BFS. OCaml's Option.map applies color flipping functionally. The Ocamlgraph library provides Coloring.check_bipartite. OCaml's for v in adj.(u) do ... is idiomatic for adjacency list traversal.
Full Source
#![allow(clippy::all)]
//! # Bipartite Check
pub fn is_bipartite(n: usize, edges: &[(usize, usize)]) -> bool {
let mut adj = vec![vec![]; n];
for &(u, v) in edges {
adj[u].push(v);
adj[v].push(u);
}
let mut color = vec![None; n];
fn bfs(start: usize, adj: &[Vec<usize>], color: &mut [Option<bool>]) -> bool {
use std::collections::VecDeque;
let mut q = VecDeque::new();
q.push_back(start);
color[start] = Some(true);
while let Some(u) = q.pop_front() {
for &v in &adj[u] {
if color[v].is_none() {
color[v] = Some(!color[u].unwrap());
q.push_back(v);
} else if color[v] == color[u] {
return false;
}
}
}
true
}
for v in 0..n {
if color[v].is_none() && !bfs(v, &adj, &mut color) {
return false;
}
}
true
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_bipartite() {
assert!(is_bipartite(4, &[(0, 1), (1, 2), (2, 3), (3, 0)]));
}
#[test]
fn test_not_bipartite() {
assert!(!is_bipartite(3, &[(0, 1), (1, 2), (2, 0)]));
}
}#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_bipartite() {
assert!(is_bipartite(4, &[(0, 1), (1, 2), (2, 3), (3, 0)]));
}
#[test]
fn test_not_bipartite() {
assert!(!is_bipartite(3, &[(0, 1), (1, 2), (2, 0)]));
}
}
Deep Comparison
OCaml vs Rust: Bipartite Check
Overview
See the example.rs and example.ml files for detailed implementations.
Key Differences
| Aspect | OCaml | Rust |
|---|---|---|
| Type system | Hindley-Milner | Ownership + traits |
| Memory | GC | Zero-cost abstractions |
| Mutability | Explicit ref | mut keyword |
| Error handling | Option/Result | Result<T, E> |
See README.md for detailed comparison.
Exercises
bipartite_partition(n, edges) -> Option<(Vec<usize>, Vec<usize>)> that returns the two vertex sets if bipartite, or None if not.