方法是建立dfs,并在其中加入pre变量,记录之前移动的是W还是B。外面套for循环,从1步开始逐次递增,直到在i步时可以走完(dfs返回1),break退出循环,即为最短步。
本题的关键主要是可能有走过来又走回去的无用情况。对于这道题,即使在最坏的情况,也基本上可以保证在15步以内(并未证明)达到目标状态,所以可以在dfs中加入step进行限制,step等于外面for循环中的循环变量时就结束。这样就有效避免了死循环的出现,对于处理这道题的情况比较方便。
注:以下代码未考虑起始时就满足条件的情况。
1 #include <cstdio> 2 #include <iostream> 3 #include <cstring> 4 using namespace std; 5 char a[10][10]; 6 int dir[4][2]={{0,1},{0,-1},{1,0},{-1,0}},ans,ox1=-1,ox2,oy1,oy2;//dir数组储存方向,oxoy记录两个空位 7 bool check()//检验此时棋盘是否满足条件 8 { 9 if(a[0][0]==a[1][1]&&a[1][1]==a[2][2]&&a[2][2]==a[3][3]) 10 return true; 11 if(a[3][0]==a[2][1]&&a[3][0]==a[1][2]&&a[3][0]==a[0][3]) 12 return 1; 13 for(int i=0;i<4;i++) 14 { 15 if(a[i][0]==a[i][1]&&a[i][1]==a[i][2]&&a[i][2]==a[i][3]) 16 return 1; 17 if(a[0][i]==a[1][i]&&a[1][i]==a[2][i]&&a[2][i]==a[3][i]) 18 return 1; 19 } 20 return 0; 21 } 22 bool val(int x,int y,char p)//检验位置是否合法 23 { 24 return x>=0&&x<4&&y>=0&&y<4&&a[x][y]!=p; 25 } 26 bool dfs(int x1,int y1,int x2,int y2,char pre,int step) 27 { 28 if(step==ans) 29 { 30 if(check()) return 1; 31 else return false; 32 } 33 for(int i=0;i<4;i++) 34 { 35 int xn,yn,xm,ym; 36 xn=x1+dir[i][0]; 37 xm=x2+dir[i][0]; 38 yn=y1+dir[i][1]; 39 ym=y2+dir[i][1]; 40 if(val(xn,yn,pre)) 41 { 42 swap(a[x1][y1],a[xn][yn]); 43 if(dfs(xn,yn,x2,y2,(pre=='B'?'W':'B'),step+1))return 1;//灵活运用三元运算符 44 swap(a[x1][y1],a[xn][yn]); 45 } 46 if(val(xm,ym,pre)) 47 { 48 swap(a[x2][y2],a[xm][ym]); 49 if(dfs(x1,y1,xm,ym,(pre=='B'?'W':'B'),step+1))return 1; 50 swap(a[x2][y2],a[xm][ym]); 51 } 52 } 53 return 0; 54 } 55 int main() 56 { 57 int i,x=0,j; 58 for(i=0;i<4;i++) 59 scanf("%s",a[i]); 60 for(i=0;i<4;i++) 61 { 62 for(j=0;j<4;j++) 63 { 64 if(a[i][j]=='O') 65 { 66 if(ox1==-1) 67 { 68 ox1=i;oy1=j; 69 } 70 else 71 {ox2=i;oy2=j;} 72 } 73 } 74 } 75 for(ans=1;ans<100000;ans++)//从第一步开始逐次进行 76 { 77 if(dfs(ox1,oy1,ox2,oy2,'W',0)) 78 break; 79 if(dfs(ox1,oy1,ox2,oy2,'B',0)) 80 break; 81 } 82 printf("%d ",ans); 83 return 0; 84 }