use serde::{Deserialize, Serialize};
use std::collections::{HashMap, HashSet};
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Graph {
adj: HashMap<usize, HashSet<usize>>,
n: usize,
m: usize,
directed: bool,
}
impl Graph {
pub fn new() -> Self {
Graph {
adj: HashMap::new(),
n: 0,
m: 0,
directed: false,
}
}
pub fn with_n_nodes(n: usize) -> Self {
let mut adj = HashMap::new();
for i in 0..n {
adj.insert(i, HashSet::new());
}
Graph { adj, n, m: 0, directed: false }
}
pub fn add_node(&mut self, node: usize) {
if !self.adj.contains_key(&node) {
self.adj.insert(node, HashSet::new());
self.n = self.n.max(node + 1);
}
}
pub fn add_edge(&mut self, u: usize, v: usize) {
if u == v { return; } self.add_node(u);
self.add_node(v);
if !self.adj[&u].contains(&v) {
self.adj.get_mut(&u).unwrap().insert(v);
self.adj.get_mut(&v).unwrap().insert(u);
self.m += 1;
}
}
pub fn remove_edge(&mut self, u: usize, v: usize) {
if let Some(neighbors) = self.adj.get_mut(&u) {
if neighbors.remove(&v) {
self.m -= 1;
}
}
if let Some(neighbors) = self.adj.get_mut(&v) {
neighbors.remove(&u);
}
}
pub fn remove_node(&mut self, node: usize) {
if let Some(neighbors) = self.adj.remove(&node) {
for &nb in &neighbors {
if let Some(nbs) = self.adj.get_mut(&nb) {
nbs.remove(&node);
self.m -= 1;
}
}
}
}
pub fn node_count(&self) -> usize {
self.adj.len()
}
pub fn edge_count(&self) -> usize {
self.m
}
pub fn nodes(&self) -> Vec<usize> {
self.adj.keys().copied().collect()
}
pub fn has_node(&self, node: usize) -> bool {
self.adj.contains_key(&node)
}
pub fn has_edge(&self, u: usize, v: usize) -> bool {
self.adj.get(&u).map_or(false, |s| s.contains(&v))
}
pub fn neighbors(&self, node: usize) -> Vec<usize> {
self.adj.get(&node).map_or(vec![], |s| s.iter().copied().collect())
}
pub fn degree(&self, node: usize) -> usize {
self.adj.get(&node).map_or(0, |s| s.len())
}
pub fn degrees(&self) -> Vec<(usize, usize)> {
self.adj.keys().map(|&n| (n, self.degree(n))).collect()
}
pub fn edges(&self) -> Vec<(usize, usize)> {
let mut edges = Vec::new();
let mut seen = HashSet::new();
for (&u, nbs) in &self.adj {
for &v in nbs {
let (a, b) = if u < v { (u, v) } else { (v, u) };
if seen.insert((a, b)) {
edges.push((a, b));
}
}
}
edges
}
pub fn bfs_distances(&self, source: usize) -> HashMap<usize, usize> {
let mut dist = HashMap::new();
let mut queue = std::collections::VecDeque::new();
dist.insert(source, 0);
queue.push_back(source);
while let Some(u) = queue.pop_front() {
let d = dist[&u];
for &v in &self.adj[&u] {
if !dist.contains_key(&v) {
dist.insert(v, d + 1);
queue.push_back(v);
}
}
}
dist
}
pub fn is_connected(&self) -> bool {
if self.adj.is_empty() { return true; }
let start = *self.adj.keys().next().unwrap();
let dist = self.bfs_distances(start);
dist.len() == self.adj.len()
}
pub fn connected_components(&self) -> Vec<Vec<usize>> {
let mut visited = HashSet::new();
let mut components = Vec::new();
for &node in self.adj.keys() {
if visited.contains(&node) { continue; }
let dist = self.bfs_distances(node);
let comp: Vec<usize> = dist.keys().copied().collect();
visited.extend(comp.iter().copied());
components.push(comp);
}
components
}
pub fn adjacency(&self) -> &HashMap<usize, HashSet<usize>> {
&self.adj
}
pub fn largest_component(&self) -> Graph {
let components = self.connected_components();
let largest = components.into_iter().max_by_key(|c| c.len()).unwrap_or_default();
let node_set: HashSet<usize> = largest.into_iter().collect();
let mut g = Graph::new();
for &u in &node_set {
for &v in &self.adj[&u] {
if node_set.contains(&v) && u < v {
g.add_edge(u, v);
}
}
}
g
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct DirectedGraph {
out_edges: HashMap<usize, HashSet<usize>>,
in_edges: HashMap<usize, HashSet<usize>>,
n: usize,
m: usize,
}
impl DirectedGraph {
pub fn new() -> Self {
DirectedGraph {
out_edges: HashMap::new(),
in_edges: HashMap::new(),
n: 0,
m: 0,
}
}
pub fn with_n_nodes(n: usize) -> Self {
let mut out_edges = HashMap::new();
let mut in_edges = HashMap::new();
for i in 0..n {
out_edges.insert(i, HashSet::new());
in_edges.insert(i, HashSet::new());
}
DirectedGraph { out_edges, in_edges, n, m: 0 }
}
pub fn add_node(&mut self, node: usize) {
if !self.out_edges.contains_key(&node) {
self.out_edges.insert(node, HashSet::new());
self.in_edges.insert(node, HashSet::new());
self.n = self.n.max(node + 1);
}
}
pub fn add_edge(&mut self, from: usize, to: usize) {
if from == to { return; }
self.add_node(from);
self.add_node(to);
if !self.out_edges[&from].contains(&to) {
self.out_edges.get_mut(&from).unwrap().insert(to);
self.in_edges.get_mut(&to).unwrap().insert(from);
self.m += 1;
}
}
pub fn node_count(&self) -> usize { self.out_edges.len() }
pub fn edge_count(&self) -> usize { self.m }
pub fn out_degree(&self, node: usize) -> usize {
self.out_edges.get(&node).map_or(0, |s| s.len())
}
pub fn in_degree(&self, node: usize) -> usize {
self.in_edges.get(&node).map_or(0, |s| s.len())
}
pub fn successors(&self, node: usize) -> Vec<usize> {
self.out_edges.get(&node).map_or(vec![], |s| s.iter().copied().collect())
}
pub fn predecessors(&self, node: usize) -> Vec<usize> {
self.in_edges.get(&node).map_or(vec![], |s| s.iter().copied().collect())
}
pub fn nodes(&self) -> Vec<usize> {
self.out_edges.keys().copied().collect()
}
pub fn has_edge(&self, from: usize, to: usize) -> bool {
self.out_edges.get(&from).map_or(false, |s| s.contains(&to))
}
pub fn out_edges_map(&self) -> &HashMap<usize, HashSet<usize>> {
&self.out_edges
}
pub fn to_undirected(&self) -> Graph {
let mut g = Graph::new();
for (&from, tos) in &self.out_edges {
for &to in tos {
g.add_edge(from, to);
}
}
g
}
}