Jirka Sejkora
4 years ago
6 changed files with 201 additions and 2 deletions
@ -0,0 +1,28 @@ |
|||
use db::LayoutDB; |
|||
use city::City; |
|||
use itertools::Itertools; |
|||
|
|||
mod city; |
|||
mod db; |
|||
mod combine; |
|||
|
|||
fn main() { |
|||
let mut db = LayoutDB::from_file("layouts.sqlite").expect("Failed to load the DB"); |
|||
eprintln!("Loaded the DB, {} stored layouts", db.layouts().len()); |
|||
|
|||
let city = City::read_from_file("01.in"); |
|||
eprintln!("Loaded the city file, {} houses", city.get_house_count()); |
|||
|
|||
let layouts = db.layouts(); |
|||
let sorted: Vec<_> = layouts.iter().sorted_by(|x, y| city::get_price(&city, x.houses()).cmp(&city::get_price(&city, y.houses()))).collect(); |
|||
let first = sorted[1]; |
|||
let second = sorted[0]; |
|||
eprintln!("Combining layouts (ID {}, price {}) and (ID {}, price {})", |
|||
first.id(), |
|||
city::get_price(&city, first.houses()), |
|||
second.id(), |
|||
city::get_price(&city, second.houses()), |
|||
); |
|||
|
|||
combine::try_combine(&city, first.houses(), second.houses()); |
|||
} |
@ -0,0 +1,163 @@ |
|||
use crate::city; |
|||
use crate::city::{City, House, SIZE, HOUSE_RANGE}; |
|||
use itertools::Itertools; |
|||
use std::collections::VecDeque; |
|||
|
|||
pub fn try_combine(city: &City, layout1: &Vec<House>, layout2: &Vec<House>) { |
|||
// Sorted in reverse so we can remove from the end
|
|||
let mut houses1_sorted: Vec<House> = layout1.iter().sorted_by(|h1, h2| h2.x.cmp(&h1.x)).map(|x| *x).collect(); |
|||
let mut houses2_sorted: Vec<House> = layout2.iter().sorted_by(|h1, h2| h2.x.cmp(&h1.x)).map(|x| *x).collect(); |
|||
|
|||
// TODO: We may want to maintain K left sides and K right sides to compare K^2 layouts at once at each x
|
|||
|
|||
// houses1 is left, houses2 is right
|
|||
|
|||
let mut left = LeftLine::new(); |
|||
let mut right = RightLine::new(); |
|||
|
|||
// Make sure that we include all houses initially
|
|||
while let Some(house) = houses2_sorted.pop() { |
|||
right.add_house(house); |
|||
} |
|||
|
|||
// x is the last left coordinate, x+1 is right
|
|||
for x in 0..SIZE { |
|||
// Update the lines
|
|||
while let Some(house) = houses1_sorted.last() { |
|||
if house.x == x { |
|||
left.add_house(*house); |
|||
houses1_sorted.pop(); |
|||
} else { |
|||
break; |
|||
} |
|||
} |
|||
right.remove_houses(x); |
|||
|
|||
// 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; |
|||
} |
|||
|
|||
if is_compatible(city, &left, &right) { |
|||
eprintln!("Compatible on X {}", x); |
|||
let houses: Vec<_> = layout1.iter().filter(|h| h.x <= x).chain(layout2.iter().filter(|h| h.x > x)).map(|h| *h).collect(); |
|||
eprintln!("Price {}", city::get_price(&city, &houses)); |
|||
//if let Some(price) = city::is_valid(&city, &houses) {
|
|||
// eprintln!("Merge valid with price {}", price)
|
|||
//} else {
|
|||
// eprintln!("Merge actually invalid, printing invalid merge");
|
|||
// println!("{}", houses.len());
|
|||
// for house in houses {
|
|||
// println!("{} {}", house.y, house.x);
|
|||
// }
|
|||
//}
|
|||
} else { |
|||
eprintln!("Incompatible on X {}", x); |
|||
} |
|||
} |
|||
} |
|||
|
|||
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) { |
|||
// This is an uncovered house
|
|||
eprintln!("House ({},{}) in uncovered range [{},{}]", x, y, max_left_covered_x+1, min_right_covered_x-1); |
|||
return false; |
|||
} |
|||
} |
|||
} |
|||
|
|||
true |
|||
} |
|||
|
|||
struct LeftLine { |
|||
covers: Vec<usize> |
|||
} |
|||
|
|||
struct RightLine { |
|||
covers: Vec<usize>, |
|||
houses: VecDeque<House> |
|||
} |
|||
|
|||
impl LeftLine { |
|||
pub fn new() -> Self { |
|||
// XXX: Careful, default of 0 includes covering first vertical line
|
|||
let covers = vec![0; SIZE]; |
|||
LeftLine {covers} |
|||
} |
|||
|
|||
pub fn add_house(&mut self, house: House) { |
|||
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); |
|||
} |
|||
} |
|||
|
|||
pub fn get_max_covered_x(&self, y: usize) -> usize { |
|||
self.covers[y] |
|||
} |
|||
} |
|||
|
|||
impl RightLine { |
|||
pub fn new() -> Self { |
|||
let covers = vec![usize::MAX; SIZE]; |
|||
let houses = VecDeque::new(); |
|||
RightLine {covers, houses} |
|||
} |
|||
|
|||
pub fn add_house(&mut self, house: House) { |
|||
// Added houses have to always be ordered by x
|
|||
eprintln!("Added house ({},{}) to right line", house.x, house.y); |
|||
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); |
|||
} |
|||
|
|||
pub fn remove_houses(&mut self, x: usize) { |
|||
// 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(); |
|||
// TODO: Verify this intersection is correct
|
|||
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); |
|||
} |
|||
} |
|||
} else { |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
|
|||
pub fn get_min_covered_x(&self, y: usize) -> usize { |
|||
self.covers[y].min(SIZE) |
|||
} |
|||
} |
Loading…
Reference in new issue