|
发表于 2020-8-3 01:54:21
|
显示全部楼层
本帖最后由 Seawolf 于 2020-8-3 02:20 编辑
Here is an 2*3 华容道.
- 在一个 2 x 3 的板上(board)有 5 块砖瓦,用数字 1~5 来表示, 以及一块空缺用 0 来表示.
- 一次移动定义为选择 0 与一个相邻的数字(上下左右)进行交换.
- 最终当板board的结果是[[1,2,3],[4,5,0]]谜板被解开。
- 给出一个谜板的初始状态,返回最少可以通过多少次移动解开谜板,如果不能解开谜板,则返回 -1 。
- 示例:
- 输入:board = [[1,2,3],[4,0,5]]
- 输出:1
- 解释:交换 0 和 5 ,1 步完成
- 输入:board = [[1,2,3],[5,4,0]]
- 输出:-1
- 解释:没有办法完成谜板
- 输入:board = [[4,1,2],[5,0,3]]
- 输出:5
- 解释:
- 最少完成谜板的最少移动次数是 5 ,
- 一种移动路径:
- 尚未移动: [[4,1,2],[5,0,3]]
- 移动 1 次: [[4,1,2],[0,5,3]]
- 移动 2 次: [[0,1,2],[4,5,3]]
- 移动 3 次: [[1,0,2],[4,5,3]]
- 移动 4 次: [[1,2,0],[4,5,3]]
- 移动 5 次: [[1,2,3],[4,5,0]]
- 输入:board = [[3,2,4],[1,5,0]]
- 输出:14
- 提示:
- board是一个如上所述的 2 x 3 的数组.
- board[i][j]是一个[0, 1, 2, 3, 4, 5]的排列.
复制代码
- It is easier for me to think about the board as a string (e.g. "123450" is the solution). I have a map that tells me positions I can move zero from the current one. I also keep track of the zero position, so I do not have to search for it every time.
- DFS
- I am running DFS with memo to store the string and the smallest number of moves to achieve this permutation. Also, I am pruning all searches that go deeper that the best solution found so far.
- unordered_map<int, vector<int>> moves{{0,{1,3}},{1,{0,2,4}},{2,{1,5}},{3,{0,4}},{4,{3,5,1}},{5,{4,2}}};
- void dfs(string s, unordered_map<string, int>& m, int cur_zero, int swap_zero, int cur_move, int& min_moves) {
- swap(s[cur_zero], s[swap_zero]);
- if (s == "123450") min_moves = min(min_moves, cur_move);
- if (cur_move < min_moves && (m[s] == 0 || m[s] > cur_move)) {
- m[s] = cur_move;
- for (auto new_zero : moves[swap_zero]) dfs(s, m, swap_zero, new_zero, cur_move + 1, min_moves);
- }
- }
- int slidingPuzzle(vector<vector<int>>& b, int min_moves = INT_MAX) {
- string s = to_string(b[0][0]) + to_string(b[0][1]) + to_string(b[0][2])
- + to_string(b[1][0]) + to_string(b[1][1]) + to_string(b[1][2]);
-
- dfs(s, unordered_map<string, int>() = {}, s.find('0'), s.find('0'), 0, min_moves);
- return min_moves == INT_MAX ? -1 : min_moves;
- }
- BFS
- Even with the pruning, DFS solution is kind of slow for this problem. BFS is much faster, and below is the code using same ideas. Thanks @beetlecamera for good suggestions.
- unordered_map<int, vector<int>> moves{{0,{1,3}},{1,{0,2,4}},{2,{1,5}},{3,{0,4}},{4,{3,5,1}},{5,{4,2}}};
- int slidingPuzzle(vector<vector<int>>& b) {
- string s = to_string(b[0][0]) + to_string(b[0][1]) + to_string(b[0][2])
- + to_string(b[1][0]) + to_string(b[1][1]) + to_string(b[1][2]);
- unordered_map<string, int> m({{s, 0}});
- queue<pair<string, int>> q({{s, s.find('0')}});
- for (;!q.empty() && q.front().first != "123450";q.pop()) {
- for (auto new_zero : moves[q.front().second]) {
- auto str = q.front().first;
- swap(str[q.front().second], str[new_zero]);
- if (m.insert({str, m[q.front().first] + 1}).second) q.push({ str, new_zero });
- }
- }
- return q.empty() ? -1 : m[q.front().first];
- }
- Follow-up tasks:
- C++ does not have it, but in Java, we could use LinkedHashSet as both the hash and the queue (and get rid of stacks).
- We could improve the performance by using integer instead of string (e.g. 123,450). Hash operations should be faster, but we will need to write our own swap function.
- Use priority_queue to see if it boost the performance. Updated: tried this one. Looks like a hybrid between DFS and BFS. The performance is worse than DFS.
复制代码 |
|