1. 程式人生 > >bzoj1085[SCOI2005]騎士精神

bzoj1085[SCOI2005]騎士精神

++ u+ Go tps jpg 我們 math upload 叠代

傳送門

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

Sample Output

7
-1

題解

直接dfs狂T不解釋。我們考慮A*算法,也就是叠代深搜。我們考慮每一步,如果當前狀態中某一個位置的棋子與目標狀態不同,則至少需要一步才能走到。因此我們可以從小到大深度,估計步數超出範圍的則不搜索,在範圍內如果找到對應解則必定為最優解。在15步內沒有走到則輸出-1。具體實現可以看代碼。

代碼

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstdlib>
 4
#include<cstring> 5 #include<algorithm> 6 #include<cmath> 7 using namespace std; 8 int a[5][5]; 9 int ans[5][5]={{1,1,1,1,1}, 10 {0,1,1,1,1}, 11 {0,0,-1,1,1}, 12 {0,0,0,0,1}, 13 {0,0,0,0,0}}; 14 int t,an; 15 int dx[8]={1,1,-1,-1,2
,2,-2,-2}; 16 int dy[8]={2,-2,2,-2,1,-1,1,-1}; 17 char ch[10]; 18 bool can=false; 19 bool che(){ 20 int i,j; 21 for(i=0;i<5;++i){ 22 for(j=0;j<5;++j){ 23 if(a[i][j]!=ans[i][j]) return false; 24 } 25 } 26 return true; 27 } 28 bool val(int now){ 29 int i,j,bu=0; 30 for(i=0;i<5;++i){ 31 for(j=0;j<5;++j){ 32 if(a[i][j]!=ans[i][j]){ 33 bu++;if(bu+now>an) return false; 34 } 35 } 36 } 37 return true; 38 } 39 void dfs(int s,int x,int y){ 40 if(s==an){ 41 if(che()){ 42 can=true; 43 } 44 return ; 45 } 46 if(can==true) return ; 47 int i,j; 48 for(i=0;i<8;++i){ 49 int nx=x+dx[i],ny=y+dy[i]; 50 if(nx<0 || nx>=5 || ny<0 || ny>=5) continue ; 51 swap(a[x][y],a[nx][ny]); 52 if(val(s)) dfs(s+1,nx,ny); 53 swap(a[x][y],a[nx][ny]); 54 } 55 } 56 int main(){ 57 scanf("%d",&t); 58 int i,j; 59 while(t--){ 60 memset(a,0,sizeof(a)); 61 int x,y; 62 for(i=0;i<5;++i){ 63 scanf("%s",ch); 64 for(j=0;j<5;++j){ 65 if(ch[j]==*){ 66 a[i][j]=-1;x=i;y=j; 67 } 68 else a[i][j]=ch[j]-0; 69 } 70 } 71 for(an=1;an<=15;++an){ 72 dfs(0,x,y); 73 if(can){ 74 printf("%d\n",an);break ; 75 } 76 } 77 if(!can) printf("-1\n"); 78 else can=false; 79 } 80 return 0; 81 }

bzoj1085[SCOI2005]騎士精神