use std::collections::VecDeque;
#[derive(Debug, Clone, Default)]
pub struct GraphMatrix {
graph: Vec<Vec<Option<i64>>>,
n: usize,
distance: Option<Vec<Vec<i64>>>,
}
impl GraphMatrix {
#[must_use]
pub fn new(n: usize) -> Self {
let mut graph = vec![];
for i in 1..n {
graph.push(vec![None; i]);
}
Self {
graph,
n,
distance: None,
}
}
#[must_use]
pub fn num_nodes(&self) -> usize {
self.n
}
fn add_node(&mut self) {
if self.n != 0 {
self.graph.push(vec![None; self.n]);
}
self.n += 1;
}
#[must_use]
pub fn edge(&self, i: usize, j: usize) -> Option<i64> {
let (i, j) = (i, j);
if self.n <= i || self.n <= j {
return None;
}
if i == j {
return Some(0);
}
let (i, j) = if i > j { (i, j) } else { (j, i) };
let i = i - 1;
self.graph[i][j]
}
#[must_use]
pub fn neighbors(&self, node: usize) -> Vec<(usize, i64)> {
(0..self.n)
.filter_map(|j| {
if node == j {
None
} else {
self.edge(node, j).map(|value| (j, value))
}
})
.collect()
}
pub fn set_edge(&mut self, i: usize, j: usize, value: i64) {
let (i, j) = (i, j);
while self.n <= i || self.n <= j {
self.add_node();
}
if i == j {
return;
}
let (i, j) = if i > j { (i, j) } else { (j, i) };
let i = i - 1;
self.graph[i][j] = Some(value);
}
#[must_use]
pub fn dist(&self, i: usize, j: usize) -> i64 {
let (i, j) = (i, j);
if let Some(distance) = &self.distance {
if i == j {
return 0;
}
let (i, j) = if i > j { (i, j) } else { (j, i) };
let i = i - 1;
distance[i][j]
} else {
panic!("Calculate distance before")
}
}
fn set_dist_min(&mut self, i: usize, j: usize, value: i64) {
let (i, j) = (i, j);
assert!(
self.distance.is_some(),
"Cannot set distance without distance matrix"
);
if i == j {
return;
}
let (i, j) = if i > j { (i, j) } else { (j, i) };
let i = i - 1;
let value = std::cmp::min(self.distance.as_ref().unwrap()[i][j], value);
self.distance.as_mut().unwrap()[i][j] = value;
}
pub fn calculate_distance(&mut self) {
if self.distance.is_some() {
return;
}
self.distance = Some(
self.graph
.iter()
.map(|row| {
row.iter()
.map(|value| {
if value.is_some() {
1
} else {
i64::from(u32::MAX)
}
})
.collect::<Vec<i64>>()
})
.collect(),
);
for k in 0..self.n {
for i in 0..self.n {
for j in i..self.n {
let dist = self.dist(i, k) + self.dist(k, j);
self.set_dist_min(i, j, dist);
}
}
}
}
#[must_use]
pub fn get_center(&self) -> usize {
let max_distance: Vec<i64> = (0..self.n)
.map(|i| (0..self.n).map(|j| self.dist(i, j)).max().unwrap())
.collect();
let min = max_distance.iter().min().unwrap();
let mut center_list: Vec<(usize, i64)> = max_distance
.iter()
.enumerate()
.filter_map(|(node, value)| {
if value <= min {
Some((node, (0..self.n).map(|other| self.dist(node, other)).sum()))
} else {
None
}
})
.collect();
center_list.sort_by_key(|(_, dist)| *dist);
center_list[0].0
}
#[must_use]
pub fn breadth_first_search(&self, start: usize) -> VecDeque<usize> {
let mut visited = Vec::new();
let mut queue = VecDeque::from([start]);
while let Some(front) = queue.pop_front() {
visited.push(front);
let neighbors = self.neighbors(front);
let mut neighbors: Vec<_> = neighbors
.iter()
.filter_map(|(index, value)| {
if !visited.contains(index) && !queue.contains(index) {
Some((*index, *value))
} else {
None
}
})
.collect();
neighbors.sort_by_key(|(_, value)| *value);
for (next, _) in neighbors {
queue.push_back(next);
}
}
VecDeque::from(visited)
}
#[must_use]
pub fn degree(&self, node: usize) -> usize {
self.neighbors(node).len()
}
}