0773-sliding-puzzle.rs (4746B)
1/// 773. Sliding Puzzle (Hard) 2/// 3/// On an 2 x 3 board, there are five tiles labeled from 1 to 5, and an empty 4/// square represented by 0. A *move* consists of choosing 0 and a 5/// 4-directionally adjacent number and swapping it. 6/// 7/// The state of the board is solved if and only if the board is 8/// [[1,2,3],[4,5,0]]. 9/// 10/// Given the puzzle board board, return the least number of moves required so 11/// that the state of the board is solved. If it is impossible for the state of 12/// the board to be solved, return -1. 13/// 14/// *Example 1:* 15/// 16/// *Input:* board = [[1,2,3],[4,0,5]] 17/// *Output:* 1 18/// *Explanation:* Swap the 0 and the 5 in one move. 19/// 20/// *Example 2:* 21/// 22/// *Input:* board = [[1,2,3],[5,4,0]] 23/// *Output:* -1 24/// *Explanation:* No number of moves will make the board solved. 25/// 26/// *Example 3:* 27/// 28/// *Input:* board = [[4,1,2],[5,0,3]] 29/// *Output:* 5 30/// *Explanation:* 5 is the smallest number of moves that solves the board. 31/// An example path: 32/// After move 0: [[4,1,2],[5,0,3]] 33/// After move 1: [[4,1,2],[0,5,3]] 34/// After move 2: [[0,1,2],[4,5,3]] 35/// After move 3: [[1,0,2],[4,5,3]] 36/// After move 4: [[1,2,0],[4,5,3]] 37/// After move 5: [[1,2,3],[4,5,0]] 38/// 39/// *Constraints:* 40/// 41/// * board.length == 2 42/// * board[i].length == 3 43/// * 0 <= board[i][j] <= 5 44/// * Each value board[i][j] is *unique*. 45/// 46use leetcode::*; 47use std::cmp::Ordering; 48use std::collections::hash_map; 49use std::collections::{BinaryHeap, HashMap}; 50 51type Board = [u8; 6]; 52 53const FINAL: Board = [1, 2, 3, 4, 5, 0]; 54 55#[derive(Clone, Eq)] 56struct State { 57 board: Board, 58 pos: u8, 59 dist: u32, 60 cost: u32, 61} 62 63impl State { 64 fn new(board: Board, pos: u8) -> Self { 65 Self { 66 board, 67 pos, 68 dist: 0, 69 cost: Self::board_cost(board), 70 } 71 } 72 73 fn swap(&self, pos: u8) -> Self { 74 let mut board = self.board; 75 board.swap(self.pos as usize, pos as usize); 76 Self { 77 board, 78 dist: self.dist + 1, 79 cost: self.dist + 1 + Self::board_cost(board), 80 pos, 81 } 82 } 83 84 fn board_cost(board: Board) -> u32 { 85 (0..6) 86 .filter(|i| board[*i] > 0) 87 .map(|i| (i as u32).abs_diff(board[i] as u32 - 1)) 88 .sum() 89 } 90} 91 92impl PartialEq for State { 93 fn eq(&self, other: &Self) -> bool { 94 self.cost == other.cost 95 } 96} 97 98impl Ord for State { 99 fn cmp(&self, other: &Self) -> Ordering { 100 other.cost.cmp(&self.cost) 101 } 102} 103 104impl PartialOrd for State { 105 fn partial_cmp(&self, other: &Self) -> Option<Ordering> { 106 Some(self.cmp(other)) 107 } 108} 109 110struct Solution {} 111 112impl Solution { 113 fn push_swap( 114 queue: &mut BinaryHeap<State>, 115 distmap: &mut HashMap<Board, u32>, 116 state: &State, 117 pos: u8, 118 ) { 119 let nstate = state.swap(pos); 120 match distmap.entry(nstate.board) { 121 hash_map::Entry::Occupied(mut entry) => { 122 let prev_dist = entry.get_mut(); 123 if nstate.dist < *prev_dist { 124 *prev_dist = nstate.dist; 125 queue.push(nstate); 126 } 127 } 128 hash_map::Entry::Vacant(entry) => { 129 entry.insert(nstate.dist); 130 queue.push(nstate); 131 } 132 }; 133 } 134 135 pub fn sliding_puzzle(board: Vec<Vec<i32>>) -> i32 { 136 let board: Board = (0..6) 137 .map(|i| board[i / 3][i % 3] as u8) 138 .collect::<Vec<_>>() 139 .try_into() 140 .unwrap(); 141 let pos = board.iter().enumerate().find(|(_, v)| **v == 0).unwrap().0 as u8; 142 let mut queue = BinaryHeap::new(); 143 let mut distmap = HashMap::new(); 144 queue.push(State::new(board, pos)); 145 while let Some(state) = queue.pop() { 146 if state.board == FINAL { 147 return state.dist as i32; 148 } 149 Self::push_swap(&mut queue, &mut distmap, &state, (state.pos + 3) % 6); 150 if (state.pos % 3) > 0 { 151 Self::push_swap(&mut queue, &mut distmap, &state, state.pos - 1); 152 } 153 if (state.pos % 3) < 2 { 154 Self::push_swap(&mut queue, &mut distmap, &state, state.pos + 1); 155 } 156 } 157 -1 158 } 159} 160 161pub fn main() { 162 println!("{}", Solution::sliding_puzzle(arg_into(1))); 163} 164 165#[cfg(test)] 166mod tests { 167 use crate::Solution; 168 use leetcode::vvi; 169 170 #[test] 171 fn test() { 172 assert_eq!(Solution::sliding_puzzle(vvi("[[1,2,3],[4,0,5]]")), 1); 173 assert_eq!(Solution::sliding_puzzle(vvi("[[1,2,3],[5,4,0]]")), -1); 174 assert_eq!(Solution::sliding_puzzle(vvi("[[4,1,2],[5,0,3]]")), 5); 175 } 176}