时间限制: 5 Sec 内存限制: 128 MB
提交: 197 解决: 104
[提交][状态][讨论版]
题目描述
八数码问题,即在一个3×3的矩阵中有8个数(1至8)和一个空格,现在要你从一个状态转换到另一个状态,每次只能移动与空格相邻的一个数字到空格当中,问题是要你求从初始状态移动到目标状态所需的最少步数。如下图所示。
1 | 2 | 3 |
| 1 | 2 | 3 |
8 | 0 | 4 |
| 7 | 8 | 4 |
7 | 6 | 5 |
| 0 | 6 | 5 |
初始状态 目标状态
如上图所示的数据以矩阵形式给出。现在给出分别代表初始状态和目标状态的两个3*3的矩阵,请给出两个矩阵相互转化的最少步数。
输入
第1行-第3行:3个用空格分隔的整数,代表初始状态相应位置的数字,0代表空格
第4行-第6行:3个用空格分隔的整数,代表终止状态相应位置的数字,0代表空格
输出
第1行:一个整数,最小转换步数,如不能到相互转化则输出"Impossible"
样例输入
1 2 3
8 0 4
7 6 5
1 2 3
7 8 4
0 6 5
样例输出
2
关键在于判重。
#include<bits/stdc++.h>
using namespace std;
int ans[3][3],sum=-1;
struct node
{
int a[3][3];
int x,y,step;
} s;
int dir[4][2]= {{1,0},{-1,0},{0,1},{0,-1}};
set<int>se;
queue<node>q;
bool check()
{
for(int i=0; i<3; i++)
for(int j=0; j<3; j++)
if(s.a[i][j]!=ans[i][j])
return false;
return true;
}
bool in(int x,int y)
{
if(x>=0&&x<3&&y>=0&&y<3)
return true;
return false;
}
bool f(int x,int y)
{
int pp=0;
for(int i=0,k=1; i<3; i++)
for(int j=0; j<3; j++)
{
if(i==x&&j==y)
pp=pp*10;
else
pp=pp*10+s.a[i][j];
if(!s.a[i][j])
pp+=s.a[x][y];
}
if(se.count(pp))
return false;
se.insert(pp);
return true;
}
void bfs()
{
while(!q.empty())
{
s=q.front();
q.pop();
if(check())
{
sum=s.step;
break;
}
for(int i=0; i<4; i++)
{
int newx=s.x+dir[i][0];
int newy=s.y+dir[i][1];
if(!in(newx,newy))
continue;
if(!f(newx,newy))
continue;
node t=s;
swap(t.a[t.x][t.y],t.a[newx][newy]);
t.x=newx,t.y=newy,t.step=s.step+1;
q.push(t);
}
}
}
int main()
{
int t;
int p=0;
for(int i=0,k=1; i<3; i++)
for(int j=0; j<3; j++)
{
scanf("%d",&s.a[i][j]);
p=p*10+s.a[i][j];
if(s.a[i][j]==0)
s.x=i,s.y=j,s.step=0;
}
for(int i=0; i<3; i++)
for(int j=0; j<3; j++)
scanf("%d",&ans[i][j]);
se.insert(p);
q.push(s);
bfs();
if(sum<0)
printf("Impossible\n");
else
printf("%d\n",sum);
}