问题:
滑动拼图。
给定2*3的一个拼图,有1~5代表每个格子的拼图,0代表空,其他位置的拼图可以滑动到这里。
求给定现在状态的拼图,是否最终能滑动到
1 | 2 | 3 |
4 | 5 | 0 |
的状态。
可以的话,需要最少多少步。
不可以的话,返回-1。
Examples: Input: board = [[1,2,3],[4,0,5]] Output: 1 Explanation: Swap the 0 and the 5 in one move. Input: board = [[1,2,3],[5,4,0]] Output: -1 Explanation: No number of moves will make the board solved. Input: board = [[4,1,2],[5,0,3]] Output: 5 Explanation: 5 is the smallest number of moves that solves the board. An example path: After move 0: [[4,1,2],[5,0,3]] After move 1: [[4,1,2],[0,5,3]] After move 2: [[0,1,2],[4,5,3]] After move 3: [[1,0,2],[4,5,3]] After move 4: [[1,2,0],[4,5,3]] After move 5: [[1,2,3],[4,5,0]] Input: board = [[3,2,4],[1,5,0]] Output: 14 Note: board will be a 2 x 3 array as described above. board[i][j] will be a permutation of [0, 1, 2, 3, 4, 5].
解法:BFS
思路:将滑动后的每个状态作为一个node,进行queue横展开。
每个状态使用string记录。
例如:最终状态target就为:"123450"
当0在0~5位置上的时候,可以移动的选择有:
下图数字代表每个位置的index:
0 | 1 | 2 |
3 | 4 | 5 |
[0]->[1, 3]
[1]->[0,2,4]
[2]->[1,5]
[3]->[0,4]
[4]->[1,3,5] 例如上图表示
[5]->[2,4]
使用visited记录已经访问过的状态,若已经访问过,则不必再加入queue进行展开了。
代码参考:
1 class Solution { 2 public: 3 int slidingPuzzle(vector<vector<int>>& board) { 4 //for every cell i, can be move to dir[i] 5 vector<vector<int>> dir={{1,3},{0,2,4},{1,5},{0,4},{1,3,5},{2,4}}; 6 string target("123450"); 7 string cur; 8 //every condition would be a node for queue 9 for(int i=0; i<2; i++) { 10 for(int j=0; j<3; j++) { 11 cur.push_back('0'+board[i][j]); 12 } 13 } 14 //cout<< cur << endl; 15 queue<string> q; 16 unordered_set<string> visited; 17 q.push(cur); 18 int res = -1; 19 int pos_0=0; 20 string tmp; 21 while(!q.empty()) { 22 int sz=q.size(); 23 res++; 24 for(int i=0; i<sz; i++) { 25 cur = q.front(); 26 q.pop(); 27 if(cur==target) return res; 28 pos_0=cur.find('0'); 29 for(auto d:dir[pos_0]) { 30 tmp = cur; 31 swap(tmp[pos_0], tmp[d]); 32 if(visited.insert(tmp).second) { 33 q.push(tmp); 34 } 35 } 36 } 37 } 38 return -1; 39 } 40 };