2.1 最基础的“穷竭搜索” 广度优先搜索
有一个4*2的方框,里面随机填充着0-7这8个数。每次只有0可以交换相邻格子里的数。比如:
可以交换为
也可以交换为
,最终希望8个数整齐地排列为
求最小的交换次数。
输入:
0 1 2 3 4 5 6 7 1 0 2 3 4 5 6 7 7 6 5 4 3 2 1 0
输出:
0 1 28
跑个题,这题的日文注解在下一页,如果你喜欢日语的话欢迎翻页看原题注解。
思路:与前几题的bfs不同,这次的bfs没有明确的移动对象,看似任意一个数都可以当成对象移动。把0作为移动对象,那么0在地图中漫游所有的格子得到的肯定就是问题的解空间。由于题目的输入是多个case,如果对每个case都运行一遍bfs就会TLE。这时我们祭出dp技能,只需要一次bfs就将解空间算出来,以后每个case只要到解空间中去找就行了。
#include <iostream> #include <string> #include <algorithm> #include <map> #include <queue> using namespace std; map<string, int> dp; int direction[4] = { 1, -1, 4, -4 }; //************************************ // Method: bfs // FullName: bfs // Access: public // Returns: void // Qualifier: 让0漫游整个字串 //************************************ void bfs() { queue<string> que; que.push("01234567"); dp["01234567"] = 0; while (!que.empty()) { string now = que.front(); que.pop(); // p是'0'的位置 int p = 0; for (int j = 0; j < 8; ++j) { if (now[j] == '0') { p = j; break; } } for (int i = 0; i < 4; ++i) { int n = p + direction[i]; if (0 <= n && n < 8 && !(p == 3 && i == 0) && // 右上角不能再往右了 !(p == 4 && i == 1)) // 左下角不能再往左了 { string next = now; swap(next[p], next[n]); if (dp.find(next) == dp.end()) { dp[next] = dp[now] + 1; que.push(next); } } } } } ///////////////////////////SubMain////////////////////////////////// int main(int argc, char *argv[]) { bfs(); string line; while (getline(cin, line)) { line.erase(remove(line.begin(), line.end(), ' '), line.end()); cout << dp[line] << endl; } return 0; } ///////////////////////////End Sub//////////////////////////////////
知识共享署名-非商业性使用-相同方式共享:码农场 » AOJ 0121: Seven Puzzle 《挑战程序设计竞赛(第2版)》练习题答案
并不是随便抓一个当作移动对象,比如02134567就还是0,而是0作为空格,是可交换移动的
作者你好,能不能解释下这句dp.find(next) == dp.end()是什么意思 我对STL的东西不怎么懂 谢谢!
dp.find(next) == dp.end()表示不存在 我还是不理解 能详细点吗 不胜感激
我懂了。很巧妙!学习 了!
谢谢作者的代码,我可以问一下
if (dp.find(next) == dp.end())
{
dp[next] = dp[now] + 1;
que.push(next);
}
这一段的意思是不是表示如果他是一个新找到的字符串(说明是最早找到的,所以在map里面是末尾),那我们就入队?
dp.find(next) == dp.end()表示不存在
line.erase(remove(line.begin(), line.end(), ‘ ‘), line.end());这个的有什么用
删空格