- 八數碼
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";
}