use crate::algo::graph::WeightedAdjacencyMatrix;
use crate::data_structures::bit::Bit;
pub struct TspSolver {}
impl TspSolver {
#[allow(clippy::needless_range_loop)]
pub fn solve(distance: &WeightedAdjacencyMatrix, start: usize) -> (f64, Vec<usize>) {
let n = distance.node_count();
let mut memo = vec![vec![f64::INFINITY; 1 << n]; n];
for i in 0..n {
memo[i][1 << i | 1 << start] = distance[start][i];
}
let mut memo = vec![vec![f64::INFINITY; 1 << n]; n];
for i in 0..n {
memo[i][1 << i | 1 << start] = distance[start][i];
}
for r in 3..=n {
for state in BinaryCombinations::new(n, r as u32).filter(|state| state.get_bit(start)) {
for next in (0..n).filter(|&node| state.get_bit(node) && node != start) {
let prev_state = state ^ (1 << next);
let mut min_dist = f64::INFINITY;
for prev_end in
(0..n).filter(|&node| state.get_bit(node) && node != start && node != next)
{
let new_dist = memo[prev_end][prev_state] + distance[prev_end][next];
if new_dist < min_dist {
min_dist = new_dist;
}
}
memo[next][state] = min_dist;
}
}
}
let end_state = (1 << n) - 1;
let mut min_dist = f64::INFINITY;
for e in (0..start).chain(start + 1..n) {
let dist = memo[e][end_state] + distance[e][start];
if dist < min_dist {
min_dist = dist;
}
}
let mut state = end_state;
let mut last_index = start;
let mut tour = vec![start];
for _ in 1..n {
let mut best_j = usize::MAX;
let mut best_dist = f64::MAX;
for j in (0..n).filter(|&j| state.get_bit(j) && j != start) {
let dist = memo[j][state] + distance[j][last_index];
if dist < best_dist {
best_j = j;
best_dist = dist;
}
}
tour.push(best_j);
state ^= 1 << best_j;
last_index = best_j;
}
(min_dist, tour)
}
}
pub struct BinaryCombinations {
curr: usize,
r: u32,
n: usize,
}
impl Iterator for BinaryCombinations {
type Item = usize;
fn next(&mut self) -> Option<Self::Item> {
for i in self.curr..1 << self.n {
if i.count_ones() == self.r {
self.curr = i + 1;
return Some(i);
}
}
None
}
}
impl BinaryCombinations {
pub fn new(n: usize, r: u32) -> Self {
Self { curr: 0, r, n }
}
}