题目大意
添加链接描述
在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字。棋盘中留有一个空格,空格用x来表示。空格周围的棋子可以移到空格中。要求解的问题是:给出一种初始布局(初始状态)和目标布局(为了使题目简单,设目标状态为12345678x),找到一种移动方法,实现从初始布局到目标布局的转变。如果不行输出unsolved。
思路分析
八数码问题的变化版,八数码的三种解法,无非是多了存储路径,以及局面不可解的问题。我们选择使用双向dfs,
效率还是可以的,这里我采用一个优化,将四种搜索策略对称分布
//右上下左四种策略
ll dx[4] = { 0,-1,1,0 }, dy[4] = { 1,0,0,-1 };
map<ll, char> sta; //将策略映射到步骤
sta[0] = 'r', sta[1] = 'u', sta[2] = 'd', sta[3] = 'l';
对正向搜索而言,我们不断的把搜索策略对应的步骤加到上一个状态对应的步骤即可,对反向搜索而言,我们选取第i个策略进行搜索,就相当于正向采用第3-i个策略进行搜索,我们将这个策略加到反向搜索步骤的开始(具体见代码注释),当正向和反向搜索碰面的时候,我们直接先输出正向搜索的步骤,再输出反向搜索的步骤即可。
#include<iostream>
#include<string>
#include<map>
#include<queue>
#include<string.h>
using namespace std;
#define ll long long
//右上下左四种策略
ll dx[4] = { 0,-1,1,0 }, dy[4] = { 1,0,0,-1 };
int main() {
map<ll, ll> m;//0:未搜索 1:正向搜索过 2:反向搜索过
map<ll, string> step;
map<ll, char> sta; //将策略映射到步骤
sta[0] = 'r', sta[1] = 'u', sta[2] = 'd', sta[3] = 'l';
queue<ll> q;
ll ss = 0, tt = 123456780, x, y;
char tmp;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
cin >> tmp;
if (tmp <= '9' && tmp >= '0')ss = ss * 10 + tmp - '0';
else {
ss *= 10;
}
}
}
q.push(ss); q.push(tt); m[ss] = 1, m[tt] = 2;
while (!q.empty()) {
ll now = q.front(); q.pop(); ll c[3][3], n = now;
for (int i = 2; i >= 0; i--)
for (int j = 2; j >= 0; j--) {
c[i][j] = n % 10; n /= 10;
if (c[i][j] == 0) { x = i, y = j; }
}
for (int i = 0; i < 4; i++) {
ll xx = x + dx[i], yy = y + dy[i];
if (xx < 0 || xx>2 || yy < 0 || yy>2)continue;
swap(c[xx][yy], c[x][y]);
ll next = 0;
for (int i = 0; i < 3; i++)for (int j = 0; j < 3; j++)next = next * 10 + c[i][j];
if (m[next] == m[now]) {//衍生出的状态已经被同一方向搜索过
swap(c[xx][yy], c[x][y]); continue;
}
if (m[next] + m[now] == 3) {//正反搜索碰面,结果出世,正向搜索在前输出步骤
if (m[now] == 1)cout << step[now] + sta[i] + step[next] << endl;
else cout << step[next] + sta[3 - i] + step[now] << endl;
return 0;
}
m[next] = m[now];//搜索方向保持一致
if (m[next] == 1) { step[next] = step[now] + sta[i]; }//正向的话直接将策略放到最后
else { step[next] = sta[3 - i] + step[now]; }//反向向上相当于正向向下,取反并加到最前
q.push(next);
swap(c[xx][yy], c[x][y]);//别忘了swap
}
}
//一直到最后都没结果
cout << "unsolvable" << endl;
}