use crate::algo::graph::WeightedAdjacencyMatrix;
use crate::data_structures::bit::Bit;
pub struct TspSolver<'a> {
memo: Vec<Vec<f32>>,
distance: &'a WeightedAdjacencyMatrix,
}
impl<'a> TspSolver<'a> {
#[allow(clippy::needless_range_loop)]
pub fn solve(distance: &'a WeightedAdjacencyMatrix, start: usize) -> (f32, Vec<usize>) {
let n = distance.vertices_count();
let mut memo = vec![vec![f32::INFINITY; 1 << n]; n];
for i in 0..n {
memo[i][1 << i | 1 << start] = distance[start][i];
}
let mut solver = Self { memo, distance };
solver._solve(n, start)
}
fn _solve(&mut self, n: usize, start: usize) -> (f32, Vec<usize>) {
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 = f32::INFINITY;
for prev_end in
(0..n).filter(|&node| state.get_bit(node) && node != start && node != next)
{
let new_dist =
self.memo[prev_end][prev_state] + self.distance[prev_end][next];
if new_dist < min_dist {
min_dist = new_dist;
}
}
self.memo[next][state] = min_dist;
}
}
}
let end_state = (1 << n) - 1;
let mut min_dist = f32::INFINITY;
for e in (0..start).chain(start + 1..n) {
let dist = self.memo[e][end_state] + self.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 = f32::MAX;
for j in (0..n).filter(|&j| state.get_bit(j) && j != start) {
let dist = self.memo[j][state] + self.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 }
}
}