题目地址: http://acm.bnu.edu.cn/bnuoj/problem_show.php?pid=1071
BFS 。
先BFS预处理出所有可能。
然后分别输入起始状态和最终状态。
对应预处理时的最初状态,相应的的根据起始状态将最终状态进行转化。
然后直接输出结果即可。。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
int f[10];
void _init(){ // 路径压缩的 预处理,f[i] = i!
int i=0,tmp=1;
for(i=1;i<10;i++)
f[i]=tmp*=i;
// for(i=0;i<10;i++)cout<<f[i]<<" ";cout<<endl;
}
short que[400000][3][3];
void cpy(short a[][3],short b[][3]){ // 复制矩阵
for(int i=0;i<3;++i)
for(int j=0;j<3;++j)
a[i][j]=b[i][j];
}
int vis[400000];
int record(short a[][3]){ // 路径压缩,上次我大概提了一下,按照【八数码】这题的压缩方法。
int i,j,cnt=0,tmp[9],sum=0,num,k;
for(i=0;i<3;++i)
for(j=0;j<3;++j){
num=0;
for(k=0;k<cnt;++k)
if(a[i][j]<tmp[k]) num++;
sum+=f[cnt]*num;
tmp[cnt++]=a[i][j];
}
return sum;
}
void bfs(){
int s,t,tt,tmp,res,nor,nxr,i,j;
short K[3][3]={1,2,3,4,5,6,7,8,9}; // 预处理时,从1~9开始。
memset(vis,-1,sizeof(vis));
s=t=0;
cpy(que[0],K);
vis[record(K)]=0;
while(s<=t){
nor=record(que[s]);
for(i=0;i<2;i++) // 枚举4个位置
for(j=0;j<2;j++){
tt=t+1;
cpy(que[tt],que[s]); // 逆时针翻转。
tmp=que[tt][i][j],que[tt][i][j]=que[tt][i][j+1],que[tt][i][j+1]=que[tt][i+1][j+1],que[tt][i+1][j+1]=que[tt][i+1][j],que[tt][i+1][j]=tmp;
nxr=record(que[tt]);
if(vis[nxr]==-1){
vis[nxr]=vis[nor]+1;
++t;
}
tt=t+1;
cpy(que[tt],que[s]); // 顺时针翻转
tmp=que[tt][i][j],que[tt][i][j]=que[tt][i+1][j],que[tt][i+1][j]=que[tt][i+1][j+1],que[tt][i+1][j+1]=que[tt][i][j+1],que[tt][i][j+1]=tmp;
nxr=record(que[tt]);
if(vis[nxr]==-1){
vis[nxr]=vis[nor]+1;
++t;
}
}
++s;
}
}
int main(){
int t,i,j;
int a,S[10];
short T[3][3];
_init();
bfs();
scanf("%d",&t);
while(t--){ // 这题 不用启发式的话,需要先预BFS处理所有可能,然后0(1)输出答案。
for(i=1;i<=9;i++){
scanf("%d",&a);
S[a]=i;
}
for(i=0;i<3;i++)
for(j=0;j<3;j++){
scanf("%d",&a);
T[i][j]=S[a];
}
printf("Number Of Move(s) Needed: %d\n",vis[record(T)]);
}
return 0;
}