Submit: 3371 Solved: 1990
[Submit][Status][Discuss]
Description
在一个5×5的棋盘上有12个白色的骑士和12个黑色的骑士, 且有一个空位。在任何时候一个骑士都能按照骑
士的走法(它可以走到和它横坐标相差为1,纵坐标相差为2或者横坐标相差为2,纵坐标相差为1的格子)移动到空
位上。 给定一个初始的棋盘,怎样才能经过移动变成如下目标棋盘: 为了体现出骑士精神,他们必须以最少的步
数完成任务。
Input
第一行有一个正整数T(T<=10),表示一共有N组数据。接下来有T个5×5的矩阵,0表示白色骑士,1表示黑色骑
士,*表示空位。两组数据之间没有空行。
Output
对于每组数据都输出一行。如果能在15步以内(包括15步)到达目标状态,则输出步数,否则输出-1。
Sample Input
2
10110
01*11
10111
01001
00000
01011
110*1
01110
01010
00100
10110
01*11
10111
01001
00000
01011
110*1
01110
01010
00100
Sample Output
7
-1
-1
第一次写启发式搜索
直接dfs爆搜会TLE,于是就要用到神奇的A-star(简称A*)算法
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 using namespace std; 5 6 const char mat[5][5]={'1','1','1','1','1', 7 '0','1','1','1','1', 8 '0','0','*','1','1', 9 '0','0','0','0','1', 10 '0','0','0','0','0'}; 11 12 int T,x,y,k; 13 int mx[8]={-2,-1,1,2,2,1,-1,-2}; 14 int my[8]={1,2,2,1,-1,-2,-2,-1}; 15 char mp[10][10]; 16 bool flag; 17 18 void read() 19 { 20 flag=0; 21 for(int i=0;i<5;i++) 22 scanf("%s",mp[i]); 23 for(int i=0;i<5;i++) 24 for(int j=0;j<5;j++) 25 if(mp[i][j]=='*') x=i,y=j; 26 } 27 28 bool check() 29 { 30 for(int i=0;i<5;i++) 31 for(int j=0;j<5;j++) 32 if(mp[i][j]!=mat[i][j]) return false; 33 return true; 34 } 35 36 bool judge(int now) 37 { 38 int val=0; 39 for(int i=0;i<5;i++) 40 for(int j=0;j<5;j++) 41 if(mp[i][j]!=mat[i][j]) 42 { 43 val++; 44 if(val+now>k) return false; 45 } 46 return true; 47 } 48 49 void dfs(int now,int x,int y) 50 { 51 if(now>=k) 52 { 53 if(check()) flag=1; 54 return; 55 } 56 if(flag) return; 57 for(int i=0;i<8;i++) 58 { 59 int nx=x+mx[i],ny=y+my[i]; 60 if(nx<0||nx>4||ny<0||ny>4) continue; 61 swap(mp[x][y],mp[nx][ny]); 62 if(judge(now)) dfs(now+1,nx,ny); 63 swap(mp[x][y],mp[nx][ny]); 64 } 65 } 66 67 int main() 68 { 69 scanf("%d",&T); 70 while(T--) 71 { 72 read(); 73 for(k=1;k<=15;k++) 74 { 75 dfs(0,x,y); 76 if(flag) 77 { 78 printf("%d ",k); 79 break; 80 } 81 } 82 if(!flag) printf("-1 "); 83 } 84 return 0; 85 }