在赢得了友谊赛后, MX获得了无敌变身的技能,他带着技能在寒假去ZKY做了实习工,并在寒假结束之后获得了一大笔财富,MX为了不让这笔钱充公,决定将这笔私房钱藏起来,连MM也不告诉藏在哪,为此MM很是苦恼(有钱不让我花)。有一天MM在工作室偶然发现了一个小箱子,箱子上除了有一个3*3的密码锁外还写着“MX的私房钱”(MDZZ)。密码锁有以下四种操作:
1.使同一列中三个数同时向下移动一格,并使最下面的数字转动到同列第一行
2.使同一列中三个数同时向上移动一格,并使最上面的数字转动到同列最后一行
3.使同一行中三个数同时向右移动一格,并使最右面的数字转动到同行第一列
4.使同一行中三个数同时向左移动一格,并使最左面的数字转动到同行最后一列
由于密码锁潮湿生锈,每对密码锁进行一次操作需要1 min的时间,现在MX快回工作室了,MM需要将密码锁移动成初始状态来打开密码锁,但却不知道是否能赶在MX回来之前,聪明的你可以帮助MM计算最短开锁时间吗? (当开锁时间大于5时,则不能赶在MX回来之前打开,就认为密码锁无解)
如图初始状态为 294753618
目标解锁状态为123456789
输入第一行一个数字T,表示T组输入数据 T<=10
接下来T行,每行包含九个数字,中间无空格隔开,表示密码锁的开始状态
输出每组数据输出一行,一个数字,表示打开密码锁的最短时间,密码锁无解输出“impossible”
(当开锁时间大于5时,则不能赶在MX回来之前打开,就认为密码锁无解)
样例输入3123456789531496827846953172样例输出
03impossible
思路:每一层每一列都有两种方向,把这12种方向都列出来,判断步数,超过5步的就不入队列,因为最多搜5层,所以没有标记已经搜过的情况。12种改变的是下标,
例如1 2 3 4 5 6 7 8 9 第一行向左移动,得出的是2 3 1 4 5 6 7 8 9 ,1的下标是—+2,2 ,3 的下标都是-1,所以,next数组代表的是的是这个位置的数的下标的改变值。
#include
#include
#include
#include
using namespace std;
struct node{
int stemp;
char c[10];
}D,d;
queueq;
int main(){
int t,k,i,j,ans;
char b[10]={'1','2','3','4','5','6','7','8','9'};
int next[12][10]={
{2,-1,-1,0,0,0,0,0,0},
{1,1,-2,0,0,0,0,0,0},
{0,0,0,2,-1,-1,0,0,0},
{0,0,0,1,1,-2,0,0,0},
{0,0,0,0,0,0,2,-1,-1},
{0,0,0,0,0,0,1,1,-2},
{6,0,0,-3,0,0,-3,0,0},
{3,0,0,3,0,0,-6,0,0},
{0,6,0,0,-3,0,0,-3,0},
{0,3,0,0,3,0,0,-6,0},
{0,0,6,0,0,-3,0,0,-3},
{0,0,3,0,0,3,0,0,-6}
};
scanf("%d",&t);
while(t--){
// printf("t=%d\n",t);
scanf("%s",D.c);
queueq;
ans=0;
while(!q.empty()) q.pop();
D.stemp=0;
q.push(D);
// printf("R ");
// printf("%s %d\n",D.c,D.stemp);
while(!q.empty()){
D=q.front();
q.pop();
// printf("C ");
// printf("%s %d\n",D.c,D.stemp);
int f=0;
for(i=0;i<9;i++)
{
if(D.c[i]!=b[i]){
f=1;
break;
}
}
if(!f){
printf("%d\n",D.stemp);
ans=1;
break;
}
for(k=0;k<12;k++){
for(i=0;i<9;i++)
d.c[i+next[k][i]]=D.c[i];
d.stemp=D.stemp+1;
if(d.stemp<=5)
{
q.push(d);
// printf("R ");
// printf("%s %d\n",d.c,d.stemp);
}
}
}
if(ans==0)
printf("impossible\n");
}
}