Optimized with a maintained HouseLayout
This commit is contained in:
		
							parent
							
								
									a01fa30954
								
							
						
					
					
						commit
						d6fd306c61
					
				
					 1 changed files with 115 additions and 45 deletions
				
			
		
							
								
								
									
										162
									
								
								src/main.rs
									
									
									
									
									
								
							
							
						
						
									
										162
									
								
								src/main.rs
									
									
									
									
									
								
							|  | @ -66,58 +66,112 @@ impl House { | |||
|     } | ||||
| } | ||||
| 
 | ||||
| struct HouseLayout<'a> { | ||||
|     city: &'a City, | ||||
|     reachable: Vec<u16>, | ||||
|     houses: Vec<House>, | ||||
|     reachable_houses: usize | ||||
| } | ||||
| 
 | ||||
| impl<'a> HouseLayout<'a> { | ||||
|     pub fn new(city: &'a City) -> Self { | ||||
|         HouseLayout { city, reachable: vec![0; SIZE * SIZE], houses: Vec::new(), reachable_houses: 0 } | ||||
|     } | ||||
| 
 | ||||
|     pub fn cover_count(&self, house: House) -> u16 { | ||||
|         self.reachable[house.y * SIZE + house.x] | ||||
|     } | ||||
| 
 | ||||
|     pub fn is_covered(&self, house: House) -> bool { | ||||
|         self.cover_count(house) > 0 | ||||
|     } | ||||
| 
 | ||||
|     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 index = y as usize * SIZE + 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); | ||||
| 
 | ||||
|         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; | ||||
| 
 | ||||
|                 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.buyable_house_count | ||||
|     } | ||||
| 
 | ||||
|     pub fn price(&self) -> u32 { | ||||
|         get_price(self.city, &self.houses) | ||||
|     } | ||||
| 
 | ||||
|     pub fn houses(&self) -> &Vec<House> { | ||||
|         &self.houses | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| fn main() { | ||||
|     let city = City::read_from_file("01.in"); | ||||
| 
 | ||||
|     const AROUND_RANGE: i32 = 200; | ||||
|     const MAX_CANDIDATES: usize = 200; | ||||
|     //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); | ||||
| 
 | ||||
|     let mut best_price: Option<u32> = 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<House> = Vec::new(); | ||||
|         let mut claimed_houses = 0; | ||||
|         let mut layout = HouseLayout::new(&city); | ||||
|         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());
 | ||||
|                 if city.is_house_xy(x, y) && !layout.is_covered(house) { | ||||
|                     layout.add_house(house); | ||||
|                     break; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             let finished = claimed_houses == city.get_house_count(); | ||||
| 
 | ||||
|             if finished { | ||||
|             if layout.is_valid() { | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         let mut price = get_price(&city, &houses); | ||||
|         eprintln!("Finished random init, price: {}", price); | ||||
|         eprintln!("Finished random init, price: {}", layout.price()); | ||||
| 
 | ||||
|         const AROUND_RANGE: i32 = 50; | ||||
|         const MAX_CANDIDATES: usize = 20; | ||||
|         const MAX_FAILED_ITERATIONS: usize = 50; | ||||
|         let mut untried_houses = layout.houses().clone(); | ||||
|         untried_houses.shuffle(&mut rng); | ||||
| 
 | ||||
|         while untried_houses.len() > 0 { | ||||
|             let house = untried_houses.pop().unwrap(); | ||||
|             let mut house_index = layout.houses().iter().position(|x| *x == house).unwrap(); | ||||
| 
 | ||||
|         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 { | ||||
|  | @ -131,45 +185,61 @@ fn main() { | |||
| 
 | ||||
|             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"); | ||||
|                 //eprintln!("Did not find candidate");
 | ||||
|             } else { | ||||
|                 for (i, &candidate) in new_candidates.iter().enumerate() { | ||||
|                     if i > MAX_CANDIDATES { | ||||
|                         //eprintln!("No valid candidate");
 | ||||
|                         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); | ||||
|                     //eprint!("Found candidate {}...", i);
 | ||||
| 
 | ||||
|                     let old_price = layout.price(); | ||||
|                     layout.remove_house(house_index); | ||||
| 
 | ||||
|                     if layout.is_valid() { | ||||
|                         // The candidate is not needed, the house was unnecessary
 | ||||
|                         let new_price = layout.price(); | ||||
|                         let price_diff = new_price as i64 - old_price as i64; | ||||
|                         //eprintln!(" candidate is valid, price diff: {}.", price_diff);
 | ||||
|                         eprintln!("Removed a house, diff {}", price_diff); | ||||
|                         eprintln!("Improved price: {}", new_price); | ||||
|                         price = new_price; | ||||
|                         houses = new_houses; | ||||
|                         failed_iterations = 0; | ||||
|                         untried_houses = layout.houses().clone(); | ||||
|                         untried_houses.shuffle(&mut rng); | ||||
|                         break; | ||||
|                     } | ||||
| 
 | ||||
|                     let candidate_index = layout.add_house(candidate); | ||||
| 
 | ||||
|                     if layout.is_valid() { | ||||
|                         let new_price = layout.price(); | ||||
|                         let price_diff = new_price as i64 - old_price as i64; | ||||
|                         //eprintln!(" candidate is valid, price diff: {}.", price_diff);
 | ||||
|                         eprintln!("Improved price: {}", new_price); | ||||
|                         untried_houses = layout.houses().clone(); | ||||
|                         untried_houses.shuffle(&mut rng); | ||||
|                         break; | ||||
|                     } else { | ||||
|                         eprintln!(" candidate is invalid."); | ||||
|                         //eprintln!(" candidate is invalid.");
 | ||||
|                         layout.remove_house(candidate_index); | ||||
|                         house_index = layout.add_house(house); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|             // Successful iterations always break
 | ||||
|             failed_iterations += 1; | ||||
|         } | ||||
| 
 | ||||
|         let price = layout.price(); | ||||
|         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); | ||||
|             print_houses(&layout.houses()); | ||||
|             println!(); | ||||
|         } else { | ||||
|             eprintln!("Finished randomization, price: {}, printing", price); | ||||
|             println!("Price {}, seed {}", price, seed); | ||||
|             print_houses(&houses); | ||||
|             print_houses(&layout.houses()); | ||||
|             println!(); | ||||
|         } | ||||
|     } | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue