题意:地图上有个冰壶,0代表冰面,1代表有石头,2代表冰壶初始位置,3代表目标位置。求冰壶运动到终点的最短步数,冰壶运动有几个规则:
1、冰壶沿一个方向运动就会停不下来,除非碰到石头或者到达终点。
2、如果碰到石头,冰壶就会停在石头旁边的区域,而石头会消失,也就是从“1”变成“0”。
3、如果冰壶静止的时候挨着石头,那么冰壶就不能向这个方向运动。
4、如果没有石头或终点,冰壶会一直运动到界外,游戏失败。
5、如果步数超过十步,游戏也会失败。
规则1、2、3见图一,一个示例见图二。
思路:总结游戏规则,归纳出几种冰壶运动的情况:
1、静止时:旁边是石头时不能移动,是终点或者冰面则可以移动。
2、运动时:运动尽头是石头或终点则可以停下来,即可行,算作运动一步,尽头是冰面时则不能移动。
结合以上,对与冰壶当前位置,先判断四个方向能否移动,能移动的话再用函数jud根据当前方向终点判断是否能移动,以此进行DFS。
//#include<bits/stdc++.h>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define INF 0x3f3f3f3f
typedef long long LL;
int m,n,ans,sx,sy,gx,gy;
int maze[25][25];
bool vis[25][25];
int d[2][4]={-1,0,0,1,0,-1,1,0};
bool jud(int &x,int &y,int f){//根据当前方向的终点判断能否移动
x+=d[0][f];
y+=d[1][f];
while(x>=0&&x<n&&y>=0&&y<m){
if(maze[x][y]==1||maze[x][y]==3){
return true;
}
x+=d[0][f];
y+=d[1][f];
}
return false;
}
void dfs(int x,int y,int k){//当前坐标、步数
if(k>=ans)return;
if(x==gx&&y==gy){
ans=min(ans,k);
return;
}
int dx,dy;
for(int i=0;i<4;++i){
dx=x+d[0][i],dy=y+d[1][i];
if(dx>=0&&dx<n&&dy>=0&&dy<m&&maze[dx][dy]!=1){
if(3==maze[dx][dy]){//相邻格子是终点,步数加一,退出本次DFS
ans=1+k;
return;
}
if(jud(dx,dy,i)){//判断能否移动
if(maze[dx][dy]==1){
maze[dx][dy]=0;
dfs(dx-d[0][i],dy-d[1][i],1+k);
maze[dx][dy]=1;
}
else if(3==maze[dx][dy]){
ans=1+k;
}
}
}
}
}
int main(){
while(scanf("%d%d",&m,&n),m+n){
for(int i=0;i<n;++i){
for(int j=0;j<m;++j){
scanf("%d",&maze[i][j]);
if(maze[i][j]==2){
sx=i,sy=j;
}
if(maze[i][j]==3){
gx=i,gy=j;
}
}
}
ans=11;
dfs(sx,sy,0);
if(ans>10)ans=-1;
printf("%d\n",ans);
}
}