问题描述
如下面第一个图的九宫格中,放着 1~8 的数字卡片,还有一个格子空着。与空格子相邻的格子中的卡片可以移动到空格中。经过若干次移动,可以形成第二个图所示的局面。
我们把第一个图的局面记为:12345678.
把第二个图的局面记为:123.46758
显然是按从上到下,从左到右的顺序记录数字,空格记为句点。
本题目的任务是已知九宫的初态和终态,求最少经过多少步的移动可以到达。如果无论多少步都无法到达,则输出-1。
输入格式
输入第一行包含九宫的初态,第二行包含九宫的终态。
输出格式
输出最少的步数,如果不存在方案,则输出-1。
样例输入
12345678.
123.46758
样例输出
3
样例输入
13524678.
46758123.
样例输出
22
#include "iostream"
#include "algorithm"
#include "vector"
#include "set"
#include "string.h"
#include "ctype.h"
using namespace std;
typedef int State[9];
#define max 1000000
State st[max];
int dist[max];
int front, rear;
set<int> vis;
State goal;
void init_table()
{
vis.clear();
}
int insert_table(int s)
{
int v = 0;
for(int i=0; i<9; i++)
v = v*10 + st[s][i];
if(vis.count(v))
return 0;
else
{
vis.insert(v);
return 1;
}
}
const int dx[] = {1, -1, 0, 0};
const int dy[] = {0, 0, 1, -1};
//返回目标状态在st中的下标
int bfs()
{
front = 1;
rear = 2;
init_table();
while(front < rear)
{
State &s = st[front];
if(memcmp(s, goal, sizeof(goal)) == 0)
return front;
int z;
for(z=0; z<9; z++) //找到空格位置
if(!s[z])
break;
int x = z/3;
int y = z%3;
for(int i=0; i<4; i++)
{
int nx = x + dx[i];
int ny = y + dy[i];
if(nx >=0 && ny>=0 && nx<3 && ny<3)
{
State &t = st[rear];
memcpy(t, s, sizeof(s));
int newz = 3*nx + ny;
t[z] = s[newz];
t[newz] = s[z];
if(insert_table(rear))
{
dist[rear] = dist[front] + 1;
rear++;
}
}
}
front++;
}
return -1;
}
int main()
{
memset(dist, 0, sizeof(dist));
int i;
char a;
for(i=0; i<9; i++)
{
cin >> a;
if('0'<=a && a<='9')
st[1][i] = a - '0';
else
st[1][i] = 0;
}
for(i=0; i<9; i++)
{
cin >> a;
if('0'<=a && a<='9')
goal[i] = a - '0';
else
goal[i] = 0;
}
int ans = bfs();
if(ans > 0)
cout << dist[ans];
else
cout << -1;
return 0;
}