use std::collections::HashSet;
fn undirected_adjacency(from: &[usize], to: &[usize], n_nodes: usize) -> Vec<Vec<usize>> {
let mut sets: Vec<HashSet<usize>> = vec![HashSet::new(); n_nodes];
for i in 0..from.len() {
if from[i] != to[i] {
sets[from[i]].insert(to[i]);
sets[to[i]].insert(from[i]);
}
}
sets.into_iter()
.map(|s| {
let mut v: Vec<usize> = s.into_iter().collect();
v.sort_unstable();
v
})
.collect()
}
fn is_endpoint(adj: &[Vec<usize>], node: usize) -> bool {
adj[node].len() != 2
}
pub fn simplify_paths(from: &[usize], to: &[usize], n_nodes: usize) -> Vec<Vec<usize>> {
let adj = undirected_adjacency(from, to, n_nodes);
let mut paths: Vec<Vec<usize>> = Vec::new();
let mut seen: HashSet<(usize, usize)> = HashSet::new();
for u in 0..n_nodes {
if !is_endpoint(&adj, u) {
continue;
}
for &start in &adj[u] {
if seen.contains(&(u, start)) {
continue;
}
let mut path = vec![u];
let mut prev = u;
let mut cur = start;
loop {
path.push(cur);
if is_endpoint(&adj, cur) || cur == u {
break;
}
let nbrs = &adj[cur];
let next = if nbrs[0] == prev { nbrs[1] } else { nbrs[0] };
prev = cur;
cur = next;
}
let last = path[path.len() - 1];
let before_last = path[path.len() - 2];
seen.insert((u, start));
seen.insert((last, before_last));
paths.push(path);
}
}
paths
}
fn find(parent: &mut [usize], x: usize) -> usize {
let mut root = x;
while parent[root] != root {
root = parent[root];
}
let mut cur = x;
while parent[cur] != root {
let next = parent[cur];
parent[cur] = root;
cur = next;
}
root
}
pub fn connected_components(a: &[usize], b: &[usize], n: usize) -> Vec<i32> {
let mut parent: Vec<usize> = (0..n).collect();
for i in 0..a.len() {
let ra = find(&mut parent, a[i]);
let rb = find(&mut parent, b[i]);
if ra != rb {
parent[ra] = rb;
}
}
(0..n).map(|i| find(&mut parent, i) as i32).collect()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn collapses_degree_two_chain() {
let from = vec![0, 1, 2];
let to = vec![1, 2, 3];
let paths = simplify_paths(&from, &to, 4);
assert_eq!(paths.len(), 1);
assert_eq!(paths[0], vec![0, 1, 2, 3]);
}
#[test]
fn keeps_intersection_nodes() {
let from = vec![0, 0, 0, 0];
let to = vec![1, 2, 3, 4];
let paths = simplify_paths(&from, &to, 5);
assert_eq!(paths.len(), 4);
assert!(paths.iter().all(|p| p.len() == 2));
}
#[test]
fn components_group_connected_nodes() {
let comp = connected_components(&[0, 2], &[1, 3], 5);
assert_eq!(comp[0], comp[1]);
assert_eq!(comp[2], comp[3]);
assert_ne!(comp[0], comp[2]);
assert_ne!(comp[4], comp[0]);
}
}