- 八数码
1 问题描述
有33 共9 个格子,其中有一个格子是空的,其他格子填满了18 之间不同的数字。通过
移动格子可以改变数字和空格的位置,现在给你初状态和末状态,请你给出最少的移动步数。
2 输入格式
输入文件名为 eight. in。
给出6 行,每行有3 个数,每两个数用一个空格空开,每个数在08 之间,其中0 表示空
格。
前3 行表示初始状态,后3 行表示目标状态。
3 输出格式
输出文件名为eight.out。
输出一行一个数,表示从初始状态移动到目标状态的最少步数。
如果无解则输出?1。
4 样例
见下发/eight/eight.in(out)。
样例解释见下发/eight/eight.jpg。
这道题还是一道挺经典的广搜,再用点康托展开或者map的判重
具体看代码
#include<bits/stdc++.h>
using namespace std;
int dx[4]={-1,1,0,0},dy[4]={0,0,-1,1};
int a[500000][4][4],b[4][4],ai,aj,f[400000],o[10],fx[400000],fy[400000],c[10][10],ha;
map<int,bool> mp;
int main()
{
freopen("eight.in","r",stdin);
freopen("eight.out","w",stdout);
int ss=0;
for (int i=1; i<=3; i++)
for (int j=1; j<=3; j++)
{
scanf("%d",&a[1][i][j]);
ss=ss*10+a[1][i][j];
if (a[1][i][j]==0) {ai=i; aj=j;}
}//读入初始状况,记录0的位置
mp[ss]=true;
for (int i=1; i<=3; i++)
for (int j=1; j<=3; j++)
scanf("%d",&b[i][j]);//终点
int h=0,t=1;
fx[t]=ai,fy[t]=aj;//广搜,0的位置入队
while (h<=t)
{
h++;
bool pp;
for (int k=0; k<4; k++)
{
int x=fx[h]+dx[k],y=fy[h]+dy[k];//四个方向拓展
if (x<1||y<1||x>3||y>3) continue;
for (int l=1; l<=3; l++)
for (int p=1; p<=3; p++)
c[l][p]=a[h][l][p];//记录一个数组用来判断新的这种移动是否合法
int u=c[x][y];
c[x][y]=c[fx[h]][fy[h]];
c[fx[h]][fy[h]]=u;//移动等于交换0和它相邻的某个数字
int s=0;
for (int l=1; l<=3; l++)
for (int p=1; p<=3; p++)
s=s*10+c[l][p];//把数组压成十进制 ,容易判重
if (mp[s]==false)//map判重
{
mp[s]=true;
t++;
fx[t]=x,fy[t]=y;
f[t]=f[h]+1;//记录移动次数
pp=false;
for (int l=1; l<=3; l++)
for (int p=1; p<=3; p++)
{
a[t][l][p]=c[l][p];
if (a[t][l][p]!=b[l][p]) pp=true;
}//如果合法那么就是新状态,每次和终点比较一下,如果成立就可以
if (pp==false) {cout<<f[t]; return 0;}
}
}
}
cout<<"-1";
}