|
|
@ -2,6 +2,7 @@ use rand::prelude::{StdRng, SliceRandom}; |
|
|
|
use rand::{SeedableRng, Rng, thread_rng}; |
|
|
|
|
|
|
|
pub const SIZE: usize = 16384; |
|
|
|
pub const HOUSE_RANGE: usize = 500; |
|
|
|
|
|
|
|
pub struct City { |
|
|
|
prices: Vec<u16>, |
|
|
@ -64,6 +65,26 @@ impl House { |
|
|
|
pub fn new(x: usize, y: usize) -> Self { |
|
|
|
House { x, y } |
|
|
|
} |
|
|
|
|
|
|
|
pub fn range_rectangle(&self) -> Rectangle { |
|
|
|
let top = if self.y <= HOUSE_RANGE { 0 } else { self.y - HOUSE_RANGE }; |
|
|
|
let bottom = if self.y >= SIZE - 1 - HOUSE_RANGE { SIZE - 1 } else { self.y + HOUSE_RANGE }; |
|
|
|
let left = if self.x <= HOUSE_RANGE { 0 } else { self.x - HOUSE_RANGE }; |
|
|
|
let right = if self.x >= SIZE - 1 - HOUSE_RANGE { SIZE - 1 } else { self.x + HOUSE_RANGE }; |
|
|
|
Rectangle {top, bottom, left, right} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/// Rectangle - a 2D range with inclusive bounds
|
|
|
|
pub struct Rectangle { |
|
|
|
/// The smaller x coordinate.
|
|
|
|
left: usize, |
|
|
|
/// The bigger x coordinate.
|
|
|
|
right: usize, |
|
|
|
/// The smaller y coordinate.
|
|
|
|
top: usize, |
|
|
|
/// The bigger y coordinate.
|
|
|
|
bottom: usize, |
|
|
|
} |
|
|
|
|
|
|
|
struct HouseLayout<'a> { |
|
|
@ -87,8 +108,9 @@ impl<'a> HouseLayout<'a> { |
|
|
|
} |
|
|
|
|
|
|
|
pub fn add_house(&mut self, house: House) -> usize { |
|
|
|
for y in (house.y as i32 - 500).max(0)..=(house.y as i32 + 500).min((SIZE - 1) as i32) { |
|
|
|
for x in (house.x as i32 - 500).max(0)..=(house.x as i32 + 500).min((SIZE - 1) as i32) { |
|
|
|
let range_rect = house.range_rectangle(); |
|
|
|
for y in range_rect.top..=range_rect.bottom { |
|
|
|
for x in range_rect.left..=range_rect.right { |
|
|
|
let index = y as usize * SIZE + x as usize; |
|
|
|
|
|
|
|
if self.reachable[index] == 0 && self.city.is_house_xy(x as usize, y as usize) { |
|
|
@ -105,8 +127,9 @@ impl<'a> HouseLayout<'a> { |
|
|
|
pub fn remove_house(&mut self, index: usize) { |
|
|
|
let house = self.houses.swap_remove(index); |
|
|
|
|
|
|
|
for y in (house.y as i32 - 500).max(0)..=(house.y as i32 + 500).min((SIZE - 1) as i32) { |
|
|
|
for x in (house.x as i32 - 500).max(0)..=(house.x as i32 + 500).min((SIZE - 1) as i32) { |
|
|
|
let range_rect = house.range_rectangle(); |
|
|
|
for y in range_rect.top..=range_rect.bottom { |
|
|
|
for x in range_rect.left..=range_rect.right { |
|
|
|
let index = y as usize * SIZE + x as usize; |
|
|
|
|
|
|
|
self.reachable[index] -= 1; |
|
|
@ -134,8 +157,8 @@ impl<'a> HouseLayout<'a> { |
|
|
|
fn main() { |
|
|
|
let city = City::read_from_file("01.in"); |
|
|
|
|
|
|
|
const AROUND_RANGE: i32 = 200; |
|
|
|
const MAX_CANDIDATES: usize = 200; |
|
|
|
const AROUND_RANGE: i32 = 50; |
|
|
|
const MAX_CANDIDATES: usize = 50; |
|
|
|
//const MAX_FAILED_ITERATIONS: usize = 50;
|
|
|
|
println!("Params: AROUND_RANGE {}, MAX_CANDIDATES {}", AROUND_RANGE, MAX_CANDIDATES); |
|
|
|
eprintln!("Params: AROUND_RANGE {}, MAX_CANDIDATES {}", AROUND_RANGE, MAX_CANDIDATES); |
|
|
@ -247,8 +270,9 @@ fn main() { |
|
|
|
|
|
|
|
pub fn get_neighbors(city: &City, house: &House) -> Vec<House> { |
|
|
|
let mut neighbors = Vec::new(); |
|
|
|
for y in (house.y as i32 - 500).max(0)..=(house.y as i32 + 500).min((SIZE - 1) as i32) { |
|
|
|
for x in (house.x as i32 - 500).max(0)..=(house.x as i32 + 500).min((SIZE - 1) as i32) { |
|
|
|
let range_rect = house.range_rectangle(); |
|
|
|
for y in range_rect.top..=range_rect.bottom { |
|
|
|
for x in range_rect.left..=range_rect.right { |
|
|
|
let house = House::new(x as usize, y as usize); |
|
|
|
if city.get_price(&house) > 0 { |
|
|
|
neighbors.push(house); |
|
|
@ -282,8 +306,9 @@ fn is_valid(city: &City, houses: &Vec<House>) -> Option<u32> { |
|
|
|
for house in houses { |
|
|
|
assert!(city.prices[house.y * SIZE + house.x] > 0); |
|
|
|
|
|
|
|
for y in (house.y as i32 - 500).max(0)..=(house.y as i32 + 500).min((SIZE - 1) as i32) { |
|
|
|
for x in (house.x as i32 - 500).max(0)..=(house.x as i32 + 500).min((SIZE - 1) as i32) { |
|
|
|
let range_rect = house.range_rectangle(); |
|
|
|
for y in range_rect.top..=range_rect.bottom { |
|
|
|
for x in range_rect.left..=range_rect.right { |
|
|
|
reachable[y as usize * SIZE + x as usize] = true; |
|
|
|
} |
|
|
|
} |
|
|
@ -300,3 +325,38 @@ fn is_valid(city: &City, houses: &Vec<House>) -> Option<u32> { |
|
|
|
|
|
|
|
Some(price) |
|
|
|
} |
|
|
|
|
|
|
|
#[cfg(test)] |
|
|
|
mod tests { |
|
|
|
use super::*; |
|
|
|
|
|
|
|
#[test] |
|
|
|
fn house_rectangle_at_min() { |
|
|
|
let house = House::new(0, 0); |
|
|
|
let rect = house.range_rectangle(); |
|
|
|
assert_eq!(rect.top, 0); |
|
|
|
assert_eq!(rect.left, 0); |
|
|
|
assert_eq!(rect.right, HOUSE_RANGE); |
|
|
|
assert_eq!(rect.bottom, HOUSE_RANGE); |
|
|
|
} |
|
|
|
|
|
|
|
#[test] |
|
|
|
fn house_rectangle_at_max() { |
|
|
|
let house = House::new(SIZE - 1, SIZE - 1); |
|
|
|
let rect = house.range_rectangle(); |
|
|
|
assert_eq!(rect.top, SIZE - 1 - HOUSE_RANGE); |
|
|
|
assert_eq!(rect.left, SIZE - 1 - HOUSE_RANGE); |
|
|
|
assert_eq!(rect.right, SIZE - 1); |
|
|
|
assert_eq!(rect.bottom, SIZE - 1); |
|
|
|
} |
|
|
|
|
|
|
|
#[test] |
|
|
|
fn house_rect_in_middle() { |
|
|
|
let house = House::new(SIZE / 2, SIZE / 2); |
|
|
|
let rect = house.range_rectangle(); |
|
|
|
assert_eq!(rect.top, house.y - HOUSE_RANGE); |
|
|
|
assert_eq!(rect.left, house.x - HOUSE_RANGE); |
|
|
|
assert_eq!(rect.right, house.x + HOUSE_RANGE); |
|
|
|
assert_eq!(rect.bottom, house.y + HOUSE_RANGE); |
|
|
|
} |
|
|
|
} |