`use crate::city;` `use crate::city::{City, House, SIZE, HOUSE_RANGE};` `use itertools::Itertools;` `use std::collections::VecDeque;` `use std::collections::vec_deque::Iter;` `pub fn try_combine(city: &City, left_layouts: &Vec<&Vec>, right_layouts: &Vec<&Vec>) {` ` // Sorted in reverse so we can remove from the end` ` let mut left_houses_sorted: Vec> = left_layouts.iter()` ` .map(|l| l.iter().sorted_by(|h1, h2| h2.x.cmp(&h1.x)).map(|x| *x).collect())` ` .collect();` ` let mut right_houses_sorted: Vec> = right_layouts.iter()` ` .map(|l| l.iter().sorted_by(|h1, h2| h2.x.cmp(&h1.x)).map(|x| *x).collect())` ` .collect();` ` let mut lefts = Vec::new();` ` let mut rights = Vec::new();` ` for _ in left_layouts {` ` lefts.push(LeftLine::new());` ` }` ` for mut right_layout in right_houses_sorted {` ` let mut right = RightLine::new();` ` // Make sure that we include all houses initially` ` while let Some(house) = right_layout.pop() {` ` right.add_house(house, &city);` ` }` ` rights.push(right);` ` }` ` let mut best_price = None;` ` // x is the last left coordinate, x+1 is right` ` for x in 0..SIZE {` ` eprintln!("Starting x {}", x);` ` // Update the lines` ` for (mut left_line, mut left_houses) in lefts.iter_mut().zip(left_houses_sorted.iter_mut()) {` ` while let Some(house) = left_houses.last() {` ` if house.x == x {` ` left_line.add_house(*house, &city);` ` left_houses.pop();` ` } else {` ` break;` ` }` ` }` ` }` ` for mut right_line in rights.iter_mut() {` ` right_line.remove_houses(x, &city);` ` }` ` // Check compatibility of lines` ` if x == 0 {` ` // Cannot check this due to limitations in the implementation of LeftLine,` ` // it wouldn't be very interesting anyway.` ` continue;` ` }` ` let mut compatibles = 0;` ` let mut incompatibles = 0;` ` for (left_i, left) in lefts.iter().enumerate() {` ` for (right_i, right) in rights.iter().enumerate() {` ` if left_i == right_i {` ` // Do not compare the same layout` ` continue;` ` }` ` if is_compatible(city, &left, &right) {` ` let price = left.price + right.price;` ` if best_price.is_none() || price < best_price.unwrap() {` ` best_price = Some(price);` ` eprintln!("{} - new best score, cut on x {}, left {} - right {}, printing", price, x, left_i, right_i);` ` println!("{} - new best score, cut on x {}, left {} - right {}", price, x, left_i, right_i);` ` let new_houses: Vec<_> = left.houses().chain(right.houses()).collect();` ` println!("{}", new_houses.len());` ` for house in new_houses {` ` println!("{} {}", house.y, house.x);` ` }` ` }` ` compatibles += 1;` ` } else {` ` incompatibles += 1;` ` }` ` }` ` }` ` eprintln!("{}/{} compatible", compatibles, compatibles + incompatibles);` ` }` `}` `fn is_compatible(city: &City, left: &LeftLine, right: &RightLine) -> bool {` ` for y in 0..SIZE {` ` let max_left_covered_x = left.get_max_covered_x(y);` ` let min_right_covered_x = right.get_min_covered_x(y);` ` // This range will often be empty` ` for x in (max_left_covered_x+1)..min_right_covered_x {` ` if city.is_house_xy(x, y) {` ` return false;` ` }` ` }` ` }` ` true` `}` `struct LeftLine {` ` covers: Vec,` ` houses: Vec,` ` price: u32` `}` `struct RightLine {` ` covers: Vec,` ` houses: VecDeque,` ` price: u32` `}` `impl LeftLine {` ` pub fn new() -> Self {` ` // XXX: Careful, default of 0 includes covering first vertical line` ` let covers = vec![0; SIZE];` ` let houses = Vec::new();` ` LeftLine {covers, houses, price: 0 }` ` }` ` pub fn add_house(&mut self, house: House, city: &City) {` ` let range_rect = house.range_rectangle();` ` for y in range_rect.top..=range_rect.bottom {` ` // Should always be the max variant` ` self.covers[y] = self.covers[y].max(range_rect.right);` ` }` ` self.price += city.get_price(house) as u32;` ` self.houses.push(house);` ` }` ` pub fn get_max_covered_x(&self, y: usize) -> usize {` ` self.covers[y]` ` }` ` pub fn get_side_price(&self) -> u32 {` ` self.price` ` }` ` pub fn houses(&self) -> std::slice::Iter<'_, House> {` ` self.houses.iter()` ` }` `}` `impl RightLine {` ` pub fn new() -> Self {` ` let covers = vec![usize::MAX; SIZE];` ` let houses = VecDeque::new();` ` RightLine {covers, houses, price: 0}` ` }` ` pub fn add_house(&mut self, house: House, city: &City) {` ` // Added houses have to always be ordered by x` ` let range_rect = house.range_rectangle();` ` for y in range_rect.top..=range_rect.bottom {` ` self.covers[y] = self.covers[y].min(range_rect.left);` ` }` ` self.houses.push_back(house);` ` self.price += city.get_price(house) as u32` ` }` ` pub fn remove_houses(&mut self, x: usize, city: &City) {` ` // Has to be called with x, x+1, x+2...` ` while let Some(house) = self.houses.front() {` ` if house.x == x {` ` let removed_house = self.houses.pop_front().unwrap();` ` let removed_rect = removed_house.range_rectangle();` ` // Remove the now-outdated distances around the removed house` ` for y in removed_rect.top..=removed_rect.bottom {` ` self.covers[y] = usize::MAX;` ` }` ` // Update distances around the removed house if the area of any houses` ` // intersects the removed area` ` for house in &self.houses {` ` let house_rect = house.range_rectangle();` ` let y_intersection = if removed_house.y < house.y {` ` house_rect.top..=removed_rect.bottom` ` } else {` ` removed_rect.top..=house_rect.bottom` ` };` ` for y in y_intersection {` ` self.covers[y] = self.covers[y].min(house_rect.left);` ` }` ` }` ` self.price -= city.get_price(removed_house) as u32;` ` } else {` ` break;` ` }` ` }` ` }` ` pub fn get_min_covered_x(&self, y: usize) -> usize {` ` self.covers[y].min(SIZE)` ` }` ` pub fn get_side_price(&self) -> u32 {` ` self.price` ` }` ` pub fn houses(&self) -> Iter<'_, House> {` ` self.houses.iter()` ` }` ```} ``` ``` ```