use proconio::input; const ORIGIN: (f64, f64) = (0.0, 0.0); fn main() { input! { (n, k): (usize, usize), xy: [(f64, f64); n], } // dp[S][i][j] // S: 既に完了した注文の集合 // i: 現在位置 // j: 手持ちのピザの個数 let mut dp: Vec>>> = vec![vec![vec![None; k]; n + 1]; 1 << n]; for pos in 0..n { dp[1 << pos][pos][k - 1] = Some(calc_distance(ORIGIN, xy[pos])); } for bits in 0_usize..1 << n { for from in 0..n { for num_pizzas in 0..k { let Some(cost) = dp[bits][from][num_pizzas] else { continue; }; for to in 0..n { if bits >> to & 1 == 1 { continue; } if num_pizzas >= 1 { chmin_for_option( &mut dp[bits | 1 << to][to][num_pizzas - 1], cost + calc_distance(xy[from], xy[to]), ); } chmin_for_option( &mut dp[bits | 1 << to][to][k - 1], cost + calc_distance_via_origin(xy[from], xy[to]), ); } } } } let mut min_cost = None; for pos in 0..n { for num_pizzas in 0..k { if let Some(cost) = dp[(1 << n) - 1][pos][num_pizzas] { chmin_for_option(&mut min_cost, cost + calc_distance(xy[pos], ORIGIN)); } } } println!("{}", min_cost.unwrap()); } fn calc_distance(coord1: (f64, f64), coord2: (f64, f64)) -> f64 { (coord1.0 - coord2.0).hypot(coord1.1 - coord2.1) } fn calc_distance_via_origin(coord1: (f64, f64), coord2: (f64, f64)) -> f64 { calc_distance(coord1, ORIGIN) + calc_distance(ORIGIN, coord2) } /// If `value` is `None` or contains a value greater than `cand_value`, update it to `Some(cand_value)`. /// /// Returns whether `value` has been updated or not as a bool value. /// /// # Arguments /// /// * `value` - Reference variable to be updated. /// * `cand_value` - Candidate value for update. pub fn chmin_for_option(value: &mut Option, cand_value: T) -> bool where T: PartialOrd, { if value.as_ref().is_some_and(|cost| cost <= &cand_value) { return false; } *value = Some(cand_value); true }