lhgzbxhz 发表于 2020-8-2 18:17:57

如何求解4*4的数字华容道?

本帖最后由 lhgzbxhz 于 2020-8-3 11:05 编辑

如题,如何编程找出一个4*4数字华容道的最优解?如果求最优解有困难,求一个解即可
只需要给出设计思路、算法或伪代码即可,谢谢大家!

2020/8/3补充:
我考虑过用深搜、广搜或动态规划,但是它们从理论上的最坏情况考虑要走遍所有16!种排列
假设每一种排列占1字节,则最终会占用大约20000GB的内存空间
且不说它超过了64位程序的内存寻址上限,就算是硬盘恐怕也没有这么大
因此用搜索的方法应该是行不通的

weiter 发表于 2020-8-2 22:06:35

你可以试一下穷举法……当然这不现实

baige 发表于 2020-8-2 22:09:32

本帖最后由 baige 于 2020-8-2 22:13 编辑

dfs深度优先搜索,当然我不会.{:10_277:}
https://blog.csdn.net/yeluoxiang/article/details/102661569

Seawolf 发表于 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 。

示例:

输入:board = [,]
输出:1
解释:交换 0 和 5 ,1 步完成
输入:board = [,]
输出:-1
解释:没有办法完成谜板
输入:board = [,]
输出:5
解释:
最少完成谜板的最少移动次数是 5 ,
一种移动路径:
尚未移动: [,]
移动 1 次: [,]
移动 2 次: [,]
移动 3 次: [,]
移动 4 次: [,]
移动 5 次: [,]
输入:board = [,]
输出:14
提示:

board是一个如上所述的 2 x 3 的数组.
board是一个的排列.

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, s);
if (s == "123450") min_moves = min(min_moves, cur_move);
if (cur_move < min_moves && (m == 0 || m > cur_move)) {
    m = cur_move;
    for (auto new_zero : moves) 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) + to_string(b) + to_string(b)
    + to_string(b) + to_string(b) + to_string(b);

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) + to_string(b) + to_string(b)
    + to_string(b) + to_string(b) + to_string(b);

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) {
      auto str = q.front().first;
      swap(str, str);
      if (m.insert({str, m + 1}).second) q.push({ str, new_zero });
    }   
}
return q.empty() ? -1 : m;
}
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.

lhgzbxhz 发表于 2020-8-3 11:00:43

baige 发表于 2020-8-2 22:09
dfs深度优先搜索,当然我不会.
https://blog.csdn.net/yeluoxiang/article/details/102661569

4*4华容道理论上来说有16!种排列,深搜需要一个栈来实现递归,这样的话栈太深会导致程序崩溃(从理论上来说)

weiter 发表于 2020-8-3 17:09:24

要不去查一下4*4华容道的公式然后用代码表示出来?

405794672 发表于 2020-8-4 15:12:20

数字华容道?啥玩意?
页: [1]
查看完整版本: 如何求解4*4的数字华容道?