Combination early implementation (vertical line)
This commit is contained in:
parent
b3cf776618
commit
5b10766ab9
6 changed files with 201 additions and 2 deletions
|
@ -21,3 +21,7 @@ path = "src/main.rs"
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "import-logs"
|
name = "import-logs"
|
||||||
path = "src/import-logs.rs"
|
path = "src/import-logs.rs"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "combine"
|
||||||
|
path = "src/combine-layouts.rs"
|
||||||
|
|
|
@ -188,7 +188,7 @@ pub fn get_price(city: &City, houses: &Vec<House>) -> u32 {
|
||||||
price
|
price
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_valid(city: &City, houses: &Vec<House>) -> Option<u32> {
|
pub fn is_valid(city: &City, houses: &Vec<House>) -> Option<u32> {
|
||||||
let mut reachable = vec![false; SIZE * SIZE];
|
let mut reachable = vec![false; SIZE * SIZE];
|
||||||
let mut price = 0u32;
|
let mut price = 0u32;
|
||||||
|
|
||||||
|
|
28
src/combine-layouts.rs
Normal file
28
src/combine-layouts.rs
Normal file
|
@ -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());
|
||||||
|
}
|
163
src/combine.rs
Normal file
163
src/combine.rs
Normal file
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,6 +16,10 @@ impl SavedLayout {
|
||||||
pub fn houses(&self) -> &Vec<House> {
|
pub fn houses(&self) -> &Vec<House> {
|
||||||
&self.houses
|
&self.houses
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn id(&self) -> usize {
|
||||||
|
self.id
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LayoutDB {
|
impl LayoutDB {
|
||||||
|
|
|
@ -21,7 +21,7 @@ fn main() {
|
||||||
|
|
||||||
const MIN_WEIGHT_SCORE: f64 = 600000.;
|
const MIN_WEIGHT_SCORE: f64 = 600000.;
|
||||||
const MAX_WEIGHT_SCORE: f64 = 700000.;
|
const MAX_WEIGHT_SCORE: f64 = 700000.;
|
||||||
const DB_CHOICE_PROBABILITY: f64 = 0.9;
|
const DB_CHOICE_PROBABILITY: f64 = 0.99;
|
||||||
|
|
||||||
let mut best_price: Option<u32> = None;
|
let mut best_price: Option<u32> = None;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue