Řešení KSP úlohy 33-3-4 Obsazování území https://ksp.mff.cuni.cz/h/ulohy/33/zadani3.html#task-33-3-4
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

#### 313 lines 8.4 KiB Raw Blame History

 `use std::fmt;` `use std::fmt::Formatter;` `pub const INPUT_CITY_WIDTH: usize = 16384;` `pub const INPUT_CITY_HEIGHT: usize = 16384;` `pub const HOUSE_RANGE: usize = 500;` `pub struct City {` ` prices: Vec,` ` buyable_house_count: usize,` ` width: usize,` ` height: usize` `}` `impl City {` ` pub fn read_from_file(filename: &str, width: usize, height: usize) -> Self {` ` let values = std::fs::read(filename).unwrap();` ` let mut prices: Vec = Vec::new();` ` for y in 0..height {` ` for x in 0..width {` ` let price = (values[(y * width + x) * 2] as u16) | ((values[(y * width + x) * 2 + 1] as u16) << 8);` ` prices.push(price);` ` }` ` }` ` City::new(prices, width, height)` ` }` ` pub fn new(prices: Vec, width: usize, height: usize) -> Self {` ` let mut buyable_house_count = 0;` ` for &price in &prices {` ` if price > 0 {` ` buyable_house_count += 1;` ` }` ` }` ` City { prices, buyable_house_count, width, height }` ` }` ` #[inline]` ` pub fn get_price(&self, house: House) -> u16 {` ` self.prices[house.y * self.width + house.x]` ` }` ` #[inline]` ` pub fn get_price_xy(&self, x: usize, y: usize) -> u16 {` ` self.prices[y * self.width + x]` ` }` ` #[inline]` ` pub fn is_house(&self, house: House) -> bool {` ` self.get_price(house) > 0` ` }` ` #[inline]` ` pub fn is_house_xy(&self, x: usize, y: usize) -> bool {` ` self.get_price_xy(x, y) > 0` ` }` ` #[inline]` ` pub fn get_house_count(&self) -> usize {` ` self.buyable_house_count` ` }` ` #[inline]` ` pub fn width(&self) -> usize {` ` self.width` ` }` ` #[inline]` ` pub fn height(&self) -> usize {` ` self.height` ` }` `}` `#[derive(Eq, PartialEq, Hash, Copy, Clone)]` `pub struct House {` ` pub x: usize,` ` pub y: usize,` `}` `impl House {` ` pub fn new(x: usize, y: usize) -> Self {` ` House { x, y }` ` }` ` pub fn range_rectangle(&self, city: &City) -> Rectangle {` ` let top = if self.y <= HOUSE_RANGE { 0 } else { self.y - HOUSE_RANGE };` ` let bottom = if self.y >= city.height() - 1 - HOUSE_RANGE { city.height() - 1 } else { self.y + HOUSE_RANGE };` ` let left = if self.x <= HOUSE_RANGE { 0 } else { self.x - HOUSE_RANGE };` ` let right = if self.x >= city.width() - 1 - HOUSE_RANGE { city.width() - 1 } else { self.x + HOUSE_RANGE };` ` Rectangle {top, bottom, left, right}` ` }` `}` `/// Rectangle - a 2D range with inclusive bounds` `#[derive(Clone, Copy)]` `pub struct Rectangle {` ` /// The smaller x coordinate.` ` pub left: usize,` ` /// The bigger x coordinate.` ` pub right: usize,` ` /// The smaller y coordinate.` ` pub top: usize,` ` /// The bigger y coordinate.` ` pub bottom: usize,` `}` `impl fmt::Display for Rectangle {` ` fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {` ` write!(f, "L{}-{}R T{}-{}B", self.left, self.right, self.top, self.bottom)` ` }` `}` `impl Rectangle {` ` pub fn is_inside(&self, x: usize, y: usize) -> bool {` ` self.left <= x && x <= self.right && self.top <= y && y <= self.bottom` ` }` ` pub fn width(&self) -> usize {` ` self.right - self.left` ` }` ` pub fn height(&self) -> usize {` ` self.bottom - self.top` ` }` `}` `pub struct HouseLayout<'a> {` ` pub city: &'a City,` ` reachable: Vec,` ` houses: Vec,` ` reachable_houses: usize` `}` `impl<'a> HouseLayout<'a> {` ` pub fn new(city: &'a City) -> Self {` ` HouseLayout { city, reachable: vec![0; city.width() * city.height()], houses: Vec::new(), reachable_houses: 0 }` ` }` ` pub fn cover_count(&self, house: House) -> u16 {` ` self.reachable[house.y * self.city.width + house.x]` ` }` ` pub fn cover_count_xy(&self, x: usize, y: usize) -> u16 {` ` self.reachable[y * self.city.width + x]` ` }` ` pub fn is_covered(&self, house: House) -> bool {` ` self.cover_count(house) > 0` ` }` ` pub fn add_house(&mut self, house: House) -> usize {` ` let range_rect = house.range_rectangle(self.city);` ` for y in range_rect.top..=range_rect.bottom {` ` for x in range_rect.left..=range_rect.right {` ` let index = y as usize * self.city.width + x as usize;` ` if self.reachable[index] == 0 && self.city.is_house_xy(x as usize, y as usize) {` ` self.reachable_houses += 1;` ` }` ` self.reachable[index] += 1;` ` }` ` }` ` self.houses.push(house);` ` self.houses.len() - 1` ` }` ` pub fn remove_house(&mut self, index: usize) {` ` let house = self.houses.swap_remove(index);` ` let range_rect = house.range_rectangle(self.city);` ` for y in range_rect.top..=range_rect.bottom {` ` for x in range_rect.left..=range_rect.right {` ` let index = y as usize * self.city.width + x as usize;` ` self.reachable[index] -= 1;` ` if self.reachable[index] == 0 && self.city.is_house_xy(x as usize, y as usize) {` ` self.reachable_houses -= 1;` ` }` ` }` ` }` ` }` ` pub fn is_valid(&self) -> bool {` ` self.reachable_houses == self.city.get_house_count()` ` }` ` pub fn price(&self) -> u32 {` ` get_price(self.city, &self.houses)` ` }` ` pub fn houses(&self) -> &Vec {` ` &self.houses` ` }` ` pub fn covered_houses(&self) -> usize {` ` self.reachable_houses` ` }` `}` `pub fn get_price(city: &City, houses: &Vec) -> u32 {` ` let mut price = 0u32;` ` for &house in houses {` ` price += city.get_price(house) as u32;` ` }` ` price` `}` `pub fn is_valid(city: &City, houses: &Vec) -> Option {` ` let mut reachable = vec![false; city.width() * city.height()];` ` let mut price = 0u32;` ` for house in houses {` ` assert!(city.is_house(*house));` ` let range_rect = house.range_rectangle(city);` ` for y in range_rect.top..=range_rect.bottom {` ` for x in range_rect.left..=range_rect.right {` ` reachable[y as usize * city.width() + x as usize] = true;` ` }` ` }` ` price += city.get_price(*house) as u32;` ` }` ` for y in 0..city.height {` ` for x in 0..city.width {` ` if !reachable[y * city.width + x] && city.prices[y * city.width + x] > 0 {` ` return None;` ` }` ` }` ` }` ` Some(price)` `}` `pub struct HouseDistances {` ` width: usize,` ` height: usize,` ` closest_house: Vec>,` `}` `impl HouseDistances {` ` pub fn get_closest_house(&self, house: House) -> Option {` ` self.closest_house[house.y * self.width + house.x]` ` }` ` pub fn get_closest_house_xy(&self, x: usize, y: usize) -> Option {` ` self.closest_house[y * self.width + x]` ` }` `}` `pub fn build_distances_right(city: &City) -> HouseDistances {` ` let mut closest = vec![None; city.width() * city.height()];` ` for y in 0..city.height() {` ` let mut last_house_x = None;` ` for x in (0..city.width()).rev() {` ` closest[y * city.width() + x] = match last_house_x {` ` None => None,` ` Some(last_x) => Some(House::new(last_x, y))` ` };` ` if city.is_house_xy(x, y) {` ` last_house_x = Some(x)` ` }` ` }` ` }` ` HouseDistances {` ` width: city.width,` ` height: city.height,` ` closest_house: closest` ` }` `}` `#[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);` ` //}` ```} ``` ``` ```