#[derive(Clone, Debug)]
pub struct Graph {
edges: Vec<Vec<usize>>,
pub n: usize,
}
impl Graph {
pub fn new(n: usize) -> Self {
let edges = vec![Vec::new(); n];
Graph { edges, n }
}
pub fn add_edge(&mut self, u: usize, v: usize) {
assert!(u < self.n && v < self.n, "Invalid vertex index");
self.edges[u].push(v);
self.edges[v].push(u);
}
pub fn all_hamiltonian_cycles(&self) -> Vec<Vec<usize>> {
if self.n == 0 {
return vec![];
}
if self.n == 1 {
return vec![];
}
let mut visited = vec![false; self.n];
let mut path = Vec::with_capacity(self.n);
let mut results = Vec::new();
path.push(0);
visited[0] = true;
self.dfs_hamiltonian(0, &mut visited, &mut path, &mut results);
unique_cycles(&mut results);
results
}
fn dfs_hamiltonian(
&self,
current: usize,
visited: &mut [bool],
path: &mut Vec<usize>,
results: &mut Vec<Vec<usize>>,
) {
if path.len() == self.n {
let start = path[0];
if self.edges[current].contains(&start) {
let cycle = path.clone();
results.push(cycle);
}
return;
}
for &next in &self.edges[current] {
if !visited[next] {
visited[next] = true;
path.push(next);
self.dfs_hamiltonian(next, visited, path, results);
path.pop();
visited[next] = false;
}
}
}
}
fn unique_cycles(cycles: &mut Vec<Vec<usize>>) {
for cycle in cycles.iter_mut() {
rotate_cycle_to_smallest(cycle);
let mut reversed = cycle.clone();
reversed.reverse();
rotate_cycle_to_smallest(&mut reversed);
if reversed < *cycle {
*cycle = reversed;
}
}
cycles.sort();
cycles.dedup();
}
fn rotate_cycle_to_smallest(cycle: &mut [usize]) {
if cycle.is_empty() {
return;
}
let min_val = *cycle.iter().min().unwrap();
if let Some(pos) = cycle.iter().position(|&x| x == min_val) {
cycle.rotate_left(pos);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_square() {
let mut g = Graph::new(4);
g.add_edge(0, 1);
g.add_edge(1, 2);
g.add_edge(2, 3);
g.add_edge(3, 0);
let cycles = g.all_hamiltonian_cycles();
assert_eq!(cycles, vec![vec![0, 1, 2, 3]]);
}
#[test]
fn test_no_cycle() {
let mut g = Graph::new(3);
g.add_edge(0, 1);
g.add_edge(1, 2);
let cycles = g.all_hamiltonian_cycles();
assert!(cycles.is_empty());
}
#[test]
fn test_triangle() {
let mut g = Graph::new(3);
g.add_edge(0, 1);
g.add_edge(1, 2);
g.add_edge(2, 0);
let cycles = g.all_hamiltonian_cycles();
assert_eq!(cycles, vec![vec![0, 1, 2]]);
}
#[test]
fn test_multiple_edges() {
let mut g = Graph::new(3);
g.add_edge(0, 1);
g.add_edge(1, 2);
g.add_edge(2, 0);
g.add_edge(0, 2);
let cycles = g.all_hamiltonian_cycles();
assert_eq!(cycles, vec![vec![0, 1, 2]]);
}
}