经典的bfs问题,将每个棋盘看成一个状态,从而转换为一个路径寻找问题。
用取模找0的标号坐标,假设0的位置为n
x=(n-1)/3+1, y=(n-1)%3+1;
#include<iostream>
#include<cstdio>
#include<map>
#include<set>
#include<queue>
#include<cstring>
using namespace std;
int obj=123804765;//目标状态
int ans,front=1,rear=2;//用来标记前驱结点标号,然后计算距离 ,
int s[10];
int news[10];
int dist[1000000];//记录距离 有362880个状态。。
int dx[]={-1,1,0,0};
int dy[]={0,0,-1,1};
set<int> vis;//状态判重
void itoarr(int f)//编码转数组
{
for(int i=9;i>=1;i--)
{
s[i]=f%10;
//cout<<s[i];
f/=10;
}
}
int arrtoi()//数组转编码
{
int f=0;
for(int i=1;i<=9;i++)
f=f*10+news[i];
return f;
}
bool judge(int f)//判重
{
if(vis.count(f))return false;
vis.insert(f);
return true;
}
int bfs(int k)
{
queue<int> q;
q.push(k);
while(!q.empty())
{
int f=q.front();
if(f==obj)return front;//如果到达目标结点,返回该结点下标
int zpos,x,y;
q.pop();
itoarr(f);
for(zpos=1;zpos<=9;zpos++)//找0的位置
if(!s[zpos])break;
x=(zpos-1)/3+1;y=(zpos-1)%3+1;
for(int i=0;i<4;i++)//四个方向
{
int newx=x+dx[i],newy=y+dy[i];
if(newx<1||newx>3||newy<1||newy>3)continue;
memcpy(&news,&s,sizeof(s));
int newz=(newx-1)*3+newy;
news[newz]=s[zpos];
news[zpos]=s[newz];
int nf=arrtoi();
//cout<<nf<<endl;
dist[rear]=dist[front]+1;//计算距离
if(judge(nf)) {q.push(nf);rear++;}
}
front++;//前驱附近已遍历完,标号+1
}
return 0;
}
int main()
{
scanf("%d",&ans);
vis.clear();
memset(dist,0,sizeof(dist));
cout<<dist[bfs(ans)];
return 0;
}