use std::collections::{BinaryHeap, HashSet, VecDeque};
#[allow(dead_code)]
pub struct TuttePolynomialEval {
edges: Vec<(usize, usize)>,
n: usize,
}
#[allow(dead_code)]
impl TuttePolynomialEval {
pub fn from_graph(graph: &UndirectedGraph) -> Self {
let mut edges = Vec::new();
for u in 0..graph.n {
for &v in &graph.adj[u] {
if u < v {
edges.push((u, v));
}
}
}
Self { edges, n: graph.n }
}
pub fn evaluate(&self, x: f64, y: f64) -> f64 {
self.tutte_rec(&self.edges.clone(), self.n, x, y)
}
fn components(n: usize, edges: &[(usize, usize)]) -> usize {
let max_v = edges.iter().flat_map(|&(u, v)| [u, v]).max().unwrap_or(0);
let sz = max_v.max(n.saturating_sub(1)) + 1;
let mut parent: Vec<usize> = (0..sz).collect();
fn find(parent: &mut Vec<usize>, a: usize) -> usize {
if parent[a] != a {
parent[a] = find(parent, parent[a]);
}
parent[a]
}
for &(u, v) in edges {
if u == v {
continue;
}
let ru = find(&mut parent, u);
let rv = find(&mut parent, v);
if ru != rv {
parent[ru] = rv;
}
}
let count_n = n.min(sz);
(0..count_n).filter(|&i| find(&mut parent, i) == i).count()
}
fn vertex_count(edges: &[(usize, usize)], base_n: usize) -> usize {
let mut seen: HashSet<usize> = HashSet::new();
for &(u, v) in edges {
seen.insert(u);
seen.insert(v);
}
seen.len().max(base_n)
}
fn tutte_rec(&self, edges: &[(usize, usize)], n: usize, x: f64, y: f64) -> f64 {
if edges.is_empty() {
return x.powi((n as i32) - 1);
}
let e = edges[0];
let rest: Vec<(usize, usize)> = edges[1..].to_vec();
let is_loop = e.0 == e.1;
if is_loop {
return y * self.tutte_rec(&rest, n, x, y);
}
let c_with = Self::components(n, edges);
let c_without = Self::components(n, &rest);
let is_bridge = c_without > c_with;
if is_bridge {
let contracted = self.contract_edge(&rest, e);
let new_n = n.saturating_sub(1).max(1);
return x * self.tutte_rec(&contracted, new_n, x, y);
}
let contracted = self.contract_edge(&rest, e);
let new_n = n.saturating_sub(1).max(1);
let del = self.tutte_rec(&rest, n, x, y);
let con = self.tutte_rec(&contracted, new_n, x, y);
del + con
}
fn contract_edge(&self, edges: &[(usize, usize)], e: (usize, usize)) -> Vec<(usize, usize)> {
let (u, v) = e;
edges
.iter()
.map(|&(a, b)| {
let a2 = if a == v { u } else { a };
let b2 = if b == v { u } else { b };
(a2, b2)
})
.collect()
}
}
#[allow(dead_code)]
pub struct SzemerédiRegularityLemma {
pub graph: UndirectedGraph,
pub epsilon: f64,
}
#[allow(dead_code)]
impl SzemerédiRegularityLemma {
pub fn new(graph: UndirectedGraph, epsilon: f64) -> Self {
Self { graph, epsilon }
}
pub fn density(&self, a: &[usize], b: &[usize]) -> f64 {
let b_set: HashSet<usize> = b.iter().copied().collect();
let edges: usize = a
.iter()
.map(|&u| {
self.graph.adj[u]
.iter()
.filter(|v| b_set.contains(*v))
.count()
})
.sum();
let denom = a.len() * b.len();
if denom == 0 {
0.0
} else {
edges as f64 / denom as f64
}
}
pub fn is_regular_pair(&self, a: &[usize], b: &[usize]) -> bool {
let d = self.density(a, b);
let a_half: Vec<usize> = a[..a.len() / 2].to_vec();
let b_half: Vec<usize> = b[..b.len() / 2].to_vec();
let d_sub = self.density(&a_half, &b_half);
(d - d_sub).abs() <= self.epsilon
}
pub fn partition(&self, k: usize) -> Vec<Vec<usize>> {
let n = self.graph.n;
let k = k.max(1);
let mut parts: Vec<Vec<usize>> = vec![vec![]; k];
for v in 0..n {
parts[v % k].push(v);
}
parts
}
pub fn run(&self, k: usize) -> (Vec<Vec<usize>>, usize) {
let parts = self.partition(k);
let mut regular_pairs = 0usize;
for i in 0..parts.len() {
for j in (i + 1)..parts.len() {
if self.is_regular_pair(&parts[i], &parts[j]) {
regular_pairs += 1;
}
}
}
(parts, regular_pairs)
}
}
#[allow(dead_code)]
pub struct TreewidthHeuristic {
adj: Vec<HashSet<usize>>,
n: usize,
}
#[allow(dead_code)]
impl TreewidthHeuristic {
pub fn new(graph: &UndirectedGraph) -> Self {
Self {
adj: graph.adj.clone(),
n: graph.n,
}
}
fn fill_count(&self, v: usize) -> usize {
let neighbors: Vec<usize> = self.adj[v].iter().copied().collect();
let mut fill = 0usize;
for i in 0..neighbors.len() {
for j in (i + 1)..neighbors.len() {
let a = neighbors[i];
let b = neighbors[j];
if !self.adj[a].contains(&b) {
fill += 1;
}
}
}
fill
}
pub fn run(&mut self) -> (Vec<usize>, usize) {
let mut eliminated = vec![false; self.n];
let mut order = Vec::with_capacity(self.n);
let mut tw_bound = 0usize;
for _ in 0..self.n {
let v = (0..self.n)
.filter(|&u| !eliminated[u])
.min_by_key(|&u| self.fill_count(u))
.expect(
"at least one non-eliminated vertex exists: loop runs n times for n vertices",
);
let deg = self.adj[v].len();
tw_bound = tw_bound.max(deg);
let neighbors: Vec<usize> = self.adj[v].iter().copied().collect();
for i in 0..neighbors.len() {
for j in (i + 1)..neighbors.len() {
let a = neighbors[i];
let b = neighbors[j];
if a != b {
self.adj[a].insert(b);
self.adj[b].insert(a);
}
}
}
for &u in &neighbors {
self.adj[u].remove(&v);
}
self.adj[v].clear();
eliminated[v] = true;
order.push(v);
}
(order, tw_bound)
}
}
#[derive(Clone, Debug)]
pub struct DiGraph {
pub n: usize,
pub adj: Vec<Vec<(usize, i64)>>,
}
impl DiGraph {
pub fn new(n: usize) -> Self {
Self {
n,
adj: vec![vec![]; n],
}
}
pub fn add_edge(&mut self, u: usize, v: usize, w: i64) {
self.adj[u].push((v, w));
}
pub fn bfs(&self, s: usize) -> Vec<usize> {
let mut dist = vec![usize::MAX; self.n];
let mut queue = VecDeque::new();
dist[s] = 0;
queue.push_back(s);
while let Some(u) = queue.pop_front() {
for &(v, _) in &self.adj[u] {
if dist[v] == usize::MAX {
dist[v] = dist[u] + 1;
queue.push_back(v);
}
}
}
dist
}
pub fn dfs(&self, s: usize) -> Vec<usize> {
let mut visited = vec![false; self.n];
let mut order = Vec::new();
self.dfs_visit(s, &mut visited, &mut order);
order
}
fn dfs_visit(&self, u: usize, visited: &mut Vec<bool>, order: &mut Vec<usize>) {
if visited[u] {
return;
}
visited[u] = true;
for &(v, _) in &self.adj[u] {
self.dfs_visit(v, visited, order);
}
order.push(u);
}
pub fn topo_sort(&self) -> Option<Vec<usize>> {
let mut in_degree = vec![0usize; self.n];
for u in 0..self.n {
for &(v, _) in &self.adj[u] {
in_degree[v] += 1;
}
}
let mut queue: VecDeque<usize> = (0..self.n).filter(|&u| in_degree[u] == 0).collect();
let mut order = Vec::new();
while let Some(u) = queue.pop_front() {
order.push(u);
for &(v, _) in &self.adj[u] {
in_degree[v] -= 1;
if in_degree[v] == 0 {
queue.push_back(v);
}
}
}
if order.len() == self.n {
Some(order)
} else {
None
}
}
pub fn scc(&self) -> Vec<Vec<usize>> {
let mut visited = vec![false; self.n];
let mut finish_order = Vec::new();
for u in 0..self.n {
if !visited[u] {
self.dfs_visit(u, &mut visited, &mut finish_order);
}
}
let mut transposed = DiGraph::new(self.n);
for u in 0..self.n {
for &(v, w) in &self.adj[u] {
transposed.add_edge(v, u, w);
}
}
let mut visited2 = vec![false; self.n];
let mut components = Vec::new();
for &u in finish_order.iter().rev() {
if !visited2[u] {
let mut comp = Vec::new();
transposed.dfs_visit(u, &mut visited2, &mut comp);
components.push(comp);
}
}
components
}
pub fn dijkstra(&self, s: usize) -> (Vec<i64>, Vec<Option<usize>>) {
use super::functions::*;
use std::cmp::Reverse;
let inf = i64::MAX / 2;
let mut dist = vec![inf; self.n];
let mut parent = vec![None; self.n];
dist[s] = 0;
let mut heap = BinaryHeap::new();
heap.push(Reverse((0i64, s)));
while let Some(Reverse((d, u))) = heap.pop() {
if d > dist[u] {
continue;
}
for &(v, w) in &self.adj[u] {
let nd = dist[u] + w;
if nd < dist[v] {
dist[v] = nd;
parent[v] = Some(u);
heap.push(Reverse((nd, v)));
}
}
}
(dist, parent)
}
pub fn bellman_ford(&self, s: usize) -> Option<Vec<i64>> {
let inf = i64::MAX / 2;
let mut dist = vec![inf; self.n];
dist[s] = 0;
for _ in 0..self.n - 1 {
let mut changed = false;
for u in 0..self.n {
if dist[u] == inf {
continue;
}
for &(v, w) in &self.adj[u] {
if dist[u] + w < dist[v] {
dist[v] = dist[u] + w;
changed = true;
}
}
}
if !changed {
break;
}
}
for u in 0..self.n {
if dist[u] == inf {
continue;
}
for &(v, w) in &self.adj[u] {
if dist[u] + w < dist[v] {
return None;
}
}
}
Some(dist)
}
pub fn floyd_warshall(&self) -> Vec<Vec<i64>> {
let inf = i64::MAX / 2;
let mut d = vec![vec![inf; self.n]; self.n];
for u in 0..self.n {
d[u][u] = 0;
for &(v, w) in &self.adj[u] {
d[u][v] = d[u][v].min(w);
}
}
for k in 0..self.n {
for i in 0..self.n {
for j in 0..self.n {
if d[i][k] < inf && d[k][j] < inf {
d[i][j] = d[i][j].min(d[i][k] + d[k][j]);
}
}
}
}
d
}
pub fn is_dag(&self) -> bool {
self.topo_sort().is_some()
}
pub fn reachable_count(&self, s: usize) -> usize {
let dist = self.bfs(s);
dist.iter().filter(|&&d| d != usize::MAX).count()
}
}
#[derive(Clone, Debug, Default)]
pub struct UndirectedGraph {
pub n: usize,
pub adj: Vec<HashSet<usize>>,
}
impl UndirectedGraph {
pub fn new(n: usize) -> Self {
Self {
n,
adj: vec![HashSet::new(); n],
}
}
pub fn add_edge(&mut self, u: usize, v: usize) {
if u != v {
self.adj[u].insert(v);
self.adj[v].insert(u);
}
}
pub fn bfs(&self, s: usize) -> Vec<usize> {
let mut dist = vec![usize::MAX; self.n];
let mut queue = VecDeque::new();
dist[s] = 0;
queue.push_back(s);
while let Some(u) = queue.pop_front() {
for &v in &self.adj[u] {
if dist[v] == usize::MAX {
dist[v] = dist[u] + 1;
queue.push_back(v);
}
}
}
dist
}
pub fn is_connected(&self) -> bool {
if self.n == 0 {
return true;
}
let dist = self.bfs(0);
dist.iter().all(|&d| d != usize::MAX)
}
pub fn num_components(&self) -> usize {
let mut visited = vec![false; self.n];
let mut count = 0;
for u in 0..self.n {
if !visited[u] {
count += 1;
let mut stack = vec![u];
while let Some(v) = stack.pop() {
if visited[v] {
continue;
}
visited[v] = true;
for &w in &self.adj[v] {
if !visited[w] {
stack.push(w);
}
}
}
}
}
count
}
pub fn bipartite_coloring(&self) -> Option<Vec<usize>> {
let mut color = vec![usize::MAX; self.n];
for s in 0..self.n {
if color[s] != usize::MAX {
continue;
}
color[s] = 0;
let mut queue = VecDeque::new();
queue.push_back(s);
while let Some(u) = queue.pop_front() {
for &v in &self.adj[u] {
if color[v] == usize::MAX {
color[v] = 1 - color[u];
queue.push_back(v);
} else if color[v] == color[u] {
return None;
}
}
}
}
Some(color)
}
pub fn is_bipartite(&self) -> bool {
self.bipartite_coloring().is_some()
}
pub fn all_degrees_even(&self) -> bool {
(0..self.n).all(|u| self.adj[u].len() % 2 == 0)
}
pub fn has_eulerian_circuit(&self) -> bool {
self.is_connected() && self.all_degrees_even()
}
pub fn greedy_coloring(&self) -> (usize, Vec<usize>) {
let mut color = vec![usize::MAX; self.n];
let mut max_color = 0;
for u in 0..self.n {
let neighbor_colors: HashSet<usize> = self.adj[u]
.iter()
.filter(|&&v| color[v] != usize::MAX)
.map(|&v| color[v])
.collect();
let mut c = 0;
while neighbor_colors.contains(&c) {
c += 1;
}
color[u] = c;
max_color = max_color.max(c);
}
(max_color + 1, color)
}
pub fn is_proper_coloring(&self, coloring: &[usize]) -> bool {
for u in 0..self.n {
for &v in &self.adj[u] {
if coloring[u] == coloring[v] {
return false;
}
}
}
true
}
pub fn degree(&self, u: usize) -> usize {
self.adj[u].len()
}
pub fn edge_count(&self) -> usize {
(0..self.n).map(|u| self.adj[u].len()).sum::<usize>() / 2
}
pub fn spanning_tree(&self) -> Vec<(usize, usize)> {
if self.n == 0 {
return vec![];
}
let mut in_tree = vec![false; self.n];
let mut edges = Vec::new();
in_tree[0] = true;
for _ in 0..self.n - 1 {
let mut found = false;
for u in 0..self.n {
if !in_tree[u] {
continue;
}
for &v in &self.adj[u] {
if !in_tree[v] {
in_tree[v] = true;
edges.push((u, v));
found = true;
break;
}
}
if found {
break;
}
}
}
edges
}
pub fn complete(n: usize) -> Self {
let mut g = Self::new(n);
for u in 0..n {
for v in (u + 1)..n {
g.add_edge(u, v);
}
}
g
}
pub fn path(n: usize) -> Self {
let mut g = Self::new(n);
for i in 0..n.saturating_sub(1) {
g.add_edge(i, i + 1);
}
g
}
pub fn cycle(n: usize) -> Self {
let mut g = Self::path(n);
if n >= 3 {
g.add_edge(n - 1, 0);
}
g
}
pub fn complete_bipartite(m: usize, n: usize) -> Self {
let mut g = Self::new(m + n);
for u in 0..m {
for v in m..(m + n) {
g.add_edge(u, v);
}
}
g
}
}
#[allow(dead_code)]
pub struct ExpanderChecker {
pub graph: UndirectedGraph,
}
#[allow(dead_code)]
impl ExpanderChecker {
pub fn new(graph: UndirectedGraph) -> Self {
Self { graph }
}
pub fn edge_boundary(&self, subset: &[usize]) -> usize {
let in_set: HashSet<usize> = subset.iter().copied().collect();
let mut boundary = 0usize;
for &u in &in_set {
for &v in &self.graph.adj[u] {
if !in_set.contains(&v) {
boundary += 1;
}
}
}
boundary
}
pub fn approximate_cheeger(&self) -> f64 {
let n = self.graph.n;
if n == 0 {
return 0.0;
}
let half = n / 2;
let mut min_ratio = f64::INFINITY;
for u in 0..n {
let boundary = self.edge_boundary(&[u]);
let size = 1usize;
let ratio = boundary as f64 / size as f64;
if ratio < min_ratio {
min_ratio = ratio;
}
}
if half >= 2 {
for u in 0..n {
for v in (u + 1)..n {
if u == v {
continue;
}
let boundary = self.edge_boundary(&[u, v]);
let ratio = boundary as f64 / 2.0;
if ratio < min_ratio {
min_ratio = ratio;
}
}
}
}
if min_ratio.is_infinite() {
0.0
} else {
min_ratio
}
}
pub fn is_expander(&self, threshold: f64) -> bool {
self.approximate_cheeger() >= threshold
}
}
#[allow(dead_code)]
pub struct GraphonSampler {
pub n: usize,
pub graphon: Box<dyn Fn(f64, f64) -> f64>,
}
#[allow(dead_code)]
impl GraphonSampler {
pub fn new(n: usize, graphon: Box<dyn Fn(f64, f64) -> f64>) -> Self {
Self { n, graphon }
}
pub fn sample_deterministic(&self) -> UndirectedGraph {
let mut g = UndirectedGraph::new(self.n);
for i in 0..self.n {
let xi = (i as f64 + 0.5) / self.n as f64;
for j in (i + 1)..self.n {
let xj = (j as f64 + 0.5) / self.n as f64;
let w = (self.graphon)(xi, xj);
if w > 0.5 {
g.add_edge(i, j);
}
}
}
g
}
pub fn sample_at_threshold(&self, p: f64) -> UndirectedGraph {
let mut g = UndirectedGraph::new(self.n);
for i in 0..self.n {
let xi = (i as f64 + 0.5) / self.n as f64;
for j in (i + 1)..self.n {
let xj = (j as f64 + 0.5) / self.n as f64;
let w = (self.graphon)(xi, xj);
if w > p {
g.add_edge(i, j);
}
}
}
g
}
}