use crate::{Graph, Vertex};
use crate::error::GraphError;
use crate::algorithms::{VisitorDFS, VisitorDFSAction, dfs_with_visitor};
use std::cmp::min;
pub struct Bridge<'a, T> {
pub from: &'a Vertex<T>,
pub to: &'a Vertex<T>,
}
struct CustomVisitor {
visited: Vec<bool>,
tin: Vec<usize>,
d: Vec<usize>,
bridges: Vec<(usize, usize)>,
timer: usize,
}
impl <T> VisitorDFS<T> for CustomVisitor {
fn entry_to_vertex_event(&mut self, vertex: &Vertex<T>) -> Result<VisitorDFSAction, GraphError> {
self.visited[vertex.id] = true;
self.tin[vertex.id] = self.timer;
self.d[vertex.id] = self.timer;
self.timer += 1;
Ok(VisitorDFSAction::Nothing)
}
fn entry_to_white_vertex_event(&mut self, vertex: &Vertex<T>, _parent: &Vertex<T>, grand_parent: Option<&Vertex<T>>) -> Result<VisitorDFSAction, GraphError> {
if let Some(value) = grand_parent {
if value.id == vertex.id {
return Ok(VisitorDFSAction::Break);
}
}
Ok(VisitorDFSAction::Nothing)
}
fn exit_from_white_vertex_event(&mut self, vertex: &Vertex<T>, parent: &Vertex<T>, _grand_parent: Option<&Vertex<T>>) -> Result<VisitorDFSAction, GraphError> {
self.d[parent.id] = min(self.d[parent.id], self.d[vertex.id]);
if self.d[vertex.id] > self.tin[parent.id] {
self.bridges.push((parent.id, vertex.id));
}
Ok(VisitorDFSAction::Nothing)
}
fn entry_to_grey_vertex_event(&mut self, vertex: &Vertex<T>, parent: &Vertex<T>, grand_parent: Option<&Vertex<T>>) -> Result<VisitorDFSAction, GraphError> {
if let Some(value) = grand_parent {
if value.id != vertex.id {
self.d[parent.id] = min(self.d[parent.id], self.tin[vertex.id]);
}
}
Ok(VisitorDFSAction::Nothing)
}
}
pub fn find_bridges<T>(graph: &Graph<T>) -> Result<Vec<Bridge<T>>, GraphError> {
let mut visitor = CustomVisitor { visited: vec![false; graph.size()], tin: vec![0; graph.size()], d: vec![0; graph.size()], bridges: vec![], timer: 1};
for from in 1..graph.size() {
if !visitor.visited[from] {
dfs_with_visitor(graph, graph.get_vertex(from)?, &mut visitor)?;
}
}
let mut bridges = vec![];
for pair in visitor.bridges {
bridges.push(Bridge{from: graph.get_vertex(pair.0)?, to: graph.get_vertex(pair.1)?});
}
Ok(bridges)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_find_bridges() {
let mut graph = Graph::new(7);
graph.add_edge(1, 2, 0).unwrap();
graph.add_edge(2, 1, 0).unwrap();
graph.add_edge(2, 3, 0).unwrap();
graph.add_edge(3, 2, 0).unwrap();
graph.add_edge(3, 1, 0).unwrap();
graph.add_edge(1, 3, 0).unwrap();
graph.add_edge(3, 4, 0).unwrap();
graph.add_edge(4, 3, 0).unwrap();
graph.add_edge(4, 5, 0).unwrap();
graph.add_edge(5, 4, 0).unwrap();
graph.add_edge(4, 6, 0).unwrap();
graph.add_edge(6, 4, 0).unwrap();
graph.add_edge(6, 5, 0).unwrap();
graph.add_edge(5, 6, 0).unwrap();
graph.add_edge(5, 7, 0).unwrap();
graph.add_edge(7, 5, 0).unwrap();
let mut bridges = vec![];
let res = find_bridges(&graph).unwrap();
for bridge in res {
bridges.push((bridge.from.id, bridge.to.id));
}
assert_eq!(bridges, vec![(5, 7), (3, 4)]);
}
}