Ř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.

#### 232 lines 7.5 KiB Raw Blame History

 `use rand::prelude::{StdRng, SliceRandom};` `use rand::{SeedableRng, Rng, thread_rng};` `pub const SIZE: usize = 16384;` `pub struct City {` ` prices: Vec,` ` buyable_house_count: usize` `}` `impl City {` ` pub fn read_from_file(filename: &str) -> Self {` ` let values = std::fs::read(filename).unwrap();` ` let mut prices: Vec = Vec::new();` ` for y in 0..SIZE {` ` for x in 0..SIZE {` ` let price = (values[(y * SIZE + x) * 2] as u16) | ((values[(y * SIZE + x) * 2 + 1] as u16) << 8);` ` prices.push(price);` ` }` ` }` ` City::new(prices)` ` }` ` pub fn new(prices: Vec) -> Self {` ` let mut buyable_house_count = 0;` ` for &price in &prices {` ` if price > 0 {` ` buyable_house_count += 1;` ` }` ` }` ` City { prices, buyable_house_count }` ` }` ` pub fn get_price(&self, house: &House) -> u16 {` ` self.prices[house.y * SIZE + house.x]` ` }` ` pub fn get_price_xy(&self, x: usize, y: usize) -> u16 {` ` self.prices[y * SIZE + x]` ` }` ` pub fn is_house(&self, house: &House) -> bool {` ` self.get_price(&house) > 0` ` }` ` pub fn is_house_xy(&self, x: usize, y: usize) -> bool {` ` self.get_price_xy(x, y) > 0` ` }` ` pub fn get_house_count(&self) -> usize {` ` self.buyable_house_count` ` }` `}` `#[derive(Eq, PartialEq, Hash, Copy, Clone)]` `pub struct House {` ` x: usize,` ` y: usize,` `}` `impl House {` ` pub fn new(x: usize, y: usize) -> Self {` ` House { x, y }` ` }` `}` `fn main() {` ` let city = City::read_from_file("01.in");` ` let mut best_price: Option = None;` ` loop {` ` let seed: u64 = thread_rng().gen();` ` eprintln!("Starting seed {}", seed);` ` let mut rng = StdRng::seed_from_u64(seed);` ` let mut reachable = vec![false; SIZE * SIZE];` ` let mut houses: Vec = Vec::new();` ` let mut claimed_houses = 0;` ` loop {` ` loop {` ` let x = rng.gen_range(0..SIZE);` ` let y = rng.gen_range(0..SIZE);` ` let house = House::new(x, y);` ` if city.is_house_xy(x, y) && !reachable[y * SIZE + x] {` ` 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 index = y as usize * SIZE + x as usize;` ` if !reachable[index] {` ` reachable[index] = true;` ` if city.is_house_xy(x as usize, y as usize) {` ` claimed_houses += 1;` ` }` ` }` ` }` ` }` ` houses.push(house);` ` //eprintln!("{} houses", houses.len());` ` break;` ` }` ` }` ` let finished = claimed_houses == city.get_house_count();` ` if finished {` ` break;` ` }` ` }` ` let mut price = get_price(&city, &houses);` ` eprintln!("Finished random init, price: {}", price);` ` const AROUND_RANGE: i32 = 50;` ` const MAX_CANDIDATES: usize = 20;` ` const MAX_FAILED_ITERATIONS: usize = 50;` ` let mut failed_iterations = 0;` ` while failed_iterations < MAX_FAILED_ITERATIONS {` ` let house = &houses.choose(&mut rng).unwrap();` ` let mut new_candidates = Vec::new();` ` for delta_y in -AROUND_RANGE..=AROUND_RANGE {` ` for delta_x in -AROUND_RANGE..=AROUND_RANGE {` ` let new_x = (house.x as i32 + delta_x).max(0).min(SIZE as i32 - 1) as usize;` ` let new_y = (house.y as i32 + delta_y).max(0).min(SIZE as i32 - 1) as usize;` ` if city.is_house_xy(new_x, new_y) && city.get_price_xy(new_x, new_y) < city.get_price(&house) {` ` new_candidates.push(House::new(new_x, new_y));` ` }` ` }` ` }` ` new_candidates.sort_by(|a, b| city.get_price(&a).cmp(&city.get_price(&b)));` ` if new_candidates.len() == 0 {` ` eprintln!("Did not find candidate");` ` } else {` ` for (i, &candidate) in new_candidates.iter().enumerate() {` ` if i > MAX_CANDIDATES {` ` break;` ` }` ` eprint!("Found candidate {}...", i);` ` let mut new_houses: Vec<_> = houses.to_vec().into_iter().filter(|h| &h != house).collect();` ` new_houses.push(candidate);` ` // TODO: This is_valid check could be way more efficient` ` if let Some(new_price) = is_valid(&city, &new_houses) {` ` let price_diff = new_price as i64 - price as i64;` ` eprintln!(" candidate is valid, price diff: {}.", price_diff);` ` eprintln!("Improved price: {}", new_price);` ` price = new_price;` ` houses = new_houses;` ` failed_iterations = 0;` ` break;` ` } else {` ` eprintln!(" candidate is invalid.");` ` }` ` }` ` }` ` // Successful iterations always break` ` failed_iterations += 1;` ` }` ` if best_price.is_none() || price < best_price.unwrap() {` ` best_price = Some(price);` ` eprintln!("Finished randomization, price: {}, new best, printing", price);` ` println!("Price {}, seed {}", price, seed);` ` print_houses(&houses);` ` println!();` ` } else {` ` eprintln!("Finished randomization, price: {}, printing", price);` ` println!("Price {}, seed {}", price, seed);` ` print_houses(&houses);` ` println!();` ` }` ` }` `}` `pub fn get_neighbors(city: &City, house: &House) -> Vec {` ` 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 house = House::new(x as usize, y as usize);` ` if city.get_price(&house) > 0 {` ` neighbors.push(house);` ` }` ` }` ` }` ` neighbors` `}` `fn print_houses(houses: &Vec) {` ` println!("{}", houses.len());` ` for house in houses {` ` println!("{} {}", house.y, house.x);` ` }` `}` `fn get_price(city: &City, houses: &Vec) -> u32 {` ` let mut price = 0u32;` ` for house in houses {` ` price += city.get_price(&house) as u32;` ` }` ` price` `}` `fn is_valid(city: &City, houses: &Vec) -> Option {` ` let mut reachable = vec![false; SIZE * SIZE];` ` let mut price = 0u32;` ` 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) {` ` reachable[y as usize * SIZE + x as usize] = true;` ` }` ` }` ` price += city.get_price(&house) as u32;` ` }` ` for y in 0..SIZE {` ` for x in 0..SIZE {` ` if !reachable[y * SIZE + x] && city.prices[y * SIZE + x] > 0 {` ` return None;` ` }` ` }` ` }` ` Some(price)` ```} ``` ``` ```