问题描述:
在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字。棋盘中留有一个空格,空格用0来表示。空格周围的棋子可以移到空格中。要求解的问题是:
给出一种初始布局(初始状态)和目标布局(设目标状态为123804765),找到一种最少步骤的移动方法,实现从初始布局到目标布局的转变。
输入
输入初始状态,一行九个数字,空格用0表示
输出
只有一行,该行只有一个数字,表示从初始状态到目标状态需要的最少移动次数(一定能到达目标状态)
样例输入
283104765
样例输出
4
解题思路:
这题与八数码问题I-bfs和map标记的区别就是输入方式换了,这样子输入,有种情况比如028137465(随便举的例子),由于第一个元素是0,所以我们用%去最后面的元素的时候,我们取不到0,所以我们用另外一种方式取,每次取第一个元素,将输入的数除以100000000,就可以得到第一个元素,然后%10得到就好了。
然后,这题我们用双向bfs写!
代码如下:
#include <iostream>
#include <queue>
#include <map>
using namespace std;
map<int, int>dis;
map<int, int>vis;
int e = 123804765;
int n;
int mp[4][4];
int ans;int dx[] = {0, 0, 1, -1}, dy[] = {1, -1, 0, 0};
int r, c;void fff1(int t) {int div = 100000000;for (int i = 0; i < 3; i++)for (int j = 0; j < 3; j++) {mp[i][j] = (t / div) % 10;if (mp[i][j] == 0) {r = i;c = j;}div = div / 10;}
}int fff2() {int tmp = 0;for (int i = 0; i < 3; i++)for (int j = 0; j < 3; j++) {tmp = tmp * 10 + mp[i][j];}return tmp;
}int dbfs(int s) {vis[s] = 1;//从起点开始搜标记为1vis[e] = 2;//从终点开始搜标记为2dis[s] = 0, dis[e] = 1;//这里终点距离为1,很容易想到是因为什么!想不到可以留言,我来帮你解答queue<int>q1, q2;q1.push(s);q2.push(e);while (q1.size() && q2.size()) {bool flag = 0;int t ;int v;if (q1.size() < q2.size()) {t = q1.front();q1.pop();
// cout << t << endl;flag = 1;} else {t = q2.front();q2.pop();
// cout << t << endl;flag = 0;}fff1(t);for (int i = 0; i < 4; i++) {int xx = r + dx[i], yy = c + dy[i];if (xx >= 0 && xx < 3 && yy >= 0 && yy < 3) {swap(mp[xx][yy], mp[r][c]);v = fff2();if (!dis.count(v)) {dis[v] = dis[t] + 1;vis[v] = vis[t];if (flag)q1.push(v);elseq2.push(v);} else if (vis[v] + vis[t] == 3)//相遇 {ans = dis[v] + dis[t];return ans;}swap(mp[xx][yy], mp[r][c]);}}}return -1;
}int main() {cin >> n;cout << dbfs(n) << endl;return 0;
}