use std::cmp::Ordering;
use std::collections::BinaryHeap;
pub struct Graph {
adj: Vec<Vec<(usize, f64)>>,
}
#[derive(Copy, Clone, PartialEq)]
pub struct State {
cost: f64,
position: usize,
}
impl Ord for State {
fn cmp(
&self,
other: &Self,
) -> Ordering {
other
.cost
.partial_cmp(&self.cost)
.unwrap_or(Ordering::Equal)
}
}
impl PartialOrd for State {
fn partial_cmp(
&self,
other: &Self,
) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Eq for State {}
impl Graph {
#[must_use]
pub fn new(num_nodes: usize) -> Self {
Self {
adj: vec![vec![]; num_nodes],
}
}
pub fn add_edge(
&mut self,
u: usize,
v: usize,
weight: f64,
) {
self.adj[u].push((v, weight));
}
#[must_use]
pub const fn num_nodes(&self) -> usize {
self.adj.len()
}
#[must_use]
pub fn adj(
&self,
u: usize,
) -> &[(usize, f64)] {
&self.adj[u]
}
}
#[must_use]
pub fn dijkstra(
graph: &Graph,
start_node: usize,
) -> (Vec<f64>, Vec<Option<usize>>) {
let num_nodes = graph.adj.len();
let mut dist: Vec<f64> = vec![f64::INFINITY; num_nodes];
let mut prev: Vec<Option<usize>> = vec![None; num_nodes];
let mut heap = BinaryHeap::new();
dist[start_node] = 0.0;
heap.push(State {
cost: 0.0,
position: start_node,
});
while let Some(State { cost, position }) = heap.pop() {
if cost > dist[position] {
continue;
}
for &(neighbor, weight) in &graph.adj[position] {
if dist[position] + weight < dist[neighbor] {
dist[neighbor] = dist[position] + weight;
prev[neighbor] = Some(position);
heap.push(State {
cost: dist[neighbor],
position: neighbor,
});
}
}
}
(dist, prev)
}
#[must_use]
pub fn bfs(
graph: &Graph,
start_node: usize,
) -> Vec<usize> {
let num_nodes = graph.num_nodes();
let mut dist = vec![usize::MAX; num_nodes];
let mut queue = std::collections::VecDeque::new();
dist[start_node] = 0;
queue.push_back(start_node);
while let Some(u) = queue.pop_front() {
for &(v, _) in graph.adj(u) {
if dist[v] == usize::MAX {
dist[v] = dist[u] + 1;
queue.push_back(v);
}
}
}
dist
}
#[must_use]
pub fn page_rank(
graph: &Graph,
damping_factor: f64,
tolerance: f64,
max_iter: usize,
) -> Vec<f64> {
let num_nodes = graph.num_nodes();
if num_nodes == 0 {
return vec![];
}
let initial_score = 1.0 / num_nodes as f64;
let mut scores = vec![initial_score; num_nodes];
let mut new_scores = vec![0.0; num_nodes];
let _out_degree = vec![0; num_nodes];
let out_degree: Vec<usize> = (0..num_nodes).map(|u| graph.adj(u).len()).collect();
for _ in 0..max_iter {
let mut total_sink_score = 0.0;
for u in 0..num_nodes {
if out_degree[u] == 0 {
total_sink_score += scores[u];
}
}
let base_score = (1.0 - damping_factor) / num_nodes as f64;
let sink_share = damping_factor * total_sink_score / num_nodes as f64;
new_scores.fill(base_score + sink_share);
for u in 0..num_nodes {
if out_degree[u] > 0 {
let share = damping_factor * scores[u] / out_degree[u] as f64;
for &(v, _) in graph.adj(u) {
new_scores[v] += share;
}
}
}
let mut diff = 0.0;
for i in 0..num_nodes {
diff += (new_scores[i] - scores[i]).abs();
}
scores.copy_from_slice(&new_scores);
if diff < tolerance {
break;
}
}
scores
}
#[must_use]
pub fn floyd_warshall(graph: &Graph) -> Vec<f64> {
let n = graph.num_nodes();
let mut dist = vec![f64::INFINITY; n * n];
for i in 0..n {
dist[i * n + i] = 0.0;
for &(j, w) in graph.adj(i) {
dist[i * n + j] = dist[i * n + j].min(w);
}
}
for k in 0..n {
for i in 0..n {
for j in 0..n {
let d_ik = dist[i * n + k];
let d_kj = dist[k * n + j];
if d_ik + d_kj < dist[i * n + j] {
dist[i * n + j] = d_ik + d_kj;
}
}
}
}
dist
}
#[must_use]
pub fn connected_components(graph: &Graph) -> Vec<usize> {
let num_nodes = graph.num_nodes();
let mut component = vec![usize::MAX; num_nodes];
let mut current_component = 0;
for i in 0..num_nodes {
if component[i] == usize::MAX {
let mut queue = std::collections::VecDeque::new();
queue.push_back(i);
component[i] = current_component;
while let Some(u) = queue.pop_front() {
for &(v, _) in graph.adj(u) {
if component[v] == usize::MAX {
component[v] = current_component;
queue.push_back(v);
}
}
}
current_component += 1;
}
}
component
}
#[must_use]
pub fn minimum_spanning_tree(graph: &Graph) -> Graph {
let num_nodes = graph.num_nodes();
let mut mst = Graph::new(num_nodes);
if num_nodes == 0 {
return mst;
}
let mut visited = vec![false; num_nodes];
let mut min_edge = vec![f64::INFINITY; num_nodes];
let mut parent = vec![None; num_nodes];
let mut heap = BinaryHeap::new();
for start_node in 0..num_nodes {
if visited[start_node] {
continue;
}
min_edge[start_node] = 0.0;
heap.push(State {
cost: 0.0,
position: start_node,
});
while let Some(State { cost, position: u }) = heap.pop() {
if visited[u] {
continue;
}
visited[u] = true;
if let Some(p) = parent[u] {
mst.add_edge(p, u, cost);
mst.add_edge(u, p, cost);
}
for &(v, weight) in graph.adj(u) {
if !visited[v] && weight < min_edge[v] {
min_edge[v] = weight;
parent[v] = Some(u);
heap.push(State {
cost: weight,
position: v,
});
}
}
}
}
mst
}