问题:打冰球。冰球可以往上下左右4个方向走,只有当冰球撞到墙时才会停下来,而墙会消失。当冰球紧贴墙时,不能将冰球往那个方向打。冰球出界就当输,超过10次还没将冰球打到目标位置也当输。求用最小次数将冰球打到目标位置,或输出-1表示输了。
分析:一般来说,求最小步数之类的迷宫问题都是用BFS解决的,但这题涉及到迷宫状态的变化(墙),BFS要不断记录状态的变化很复杂,不过网上好像也有人用BFS做的。DFS更加适合这种状态一直变化的,只不过要保存最优值而已,其实最优值也方便剪枝(当前步数已经是当前最优值大小但还没到达目的地也就没必要进行下去了)。需要注意的是,这题并不是移动一格,而是一直移动直到遇到障碍物。特别是目标点可能在移动的过程中到达。具体看代码。
C++代码:
#include <cstdio> const int MAX_W = ;
const int MAX_H = ; //输入
int W, H;
int g[MAX_H][MAX_W]; //起始
int sx, sy;
//目标
int ex, ey;
//4个方向
int d[][] = {{-, }, {, }, {, -}, {, }};
//最终结果
int result; bool inSquare(int x, int y){
return <= x && x < H && <= y && y < W;
} //在(x, y)位置上的步数ans
void dfs(int x, int y, int ans){
//若到达目标点
if(x == ex && y == ey){
if(result > ans){
//若有更小值
result = ans;
}
return;
}
//若超过10步,或超过当前最短步数
if(ans == || ans >= result) return;
//深度优先4个方向走
for(int i = ; i < ; i ++){
int nx = x + d[i][], ny = y + d[i][];
while(inSquare(nx, ny) && g[nx][ny] != ){
//若此方向能走,则走到尽头,直至出场或撞墙
if(nx == ex && ny == ey){
//若在过程中到达目标点
ans ++;
if(result > ans){
result = ans;
}
return;
}
nx += d[i][];
ny += d[i][];
}
if((nx == x + d[i][] && ny == y + d[i][]) || !inSquare(nx, ny)){
//此方向不能走,或出场
continue;
}
//撞墙
g[nx][ny] = ;
ans ++;
dfs(nx - d[i][], ny - d[i][], ans);
ans --;
g[nx][ny] = ;
}
} void solve(){
//初始化
result = ;
//找出起始点与终点
for(int i = ; i < H; i ++){
for(int j = ; j < W; j ++){
if(g[i][j] == ){
sx = i;
sy = j;
g[i][j] = ;
}
if(g[i][j] == ){
ex = i;
ey = j;
}
}
}
//深度优先搜索
dfs(sx, sy, );
if(result == )
printf("-1\n");
else
printf("%d\n", result);
} int main(int argc, char const *argv[]){ while(scanf("%d %d", &W, &H)){
if(W == && H == ) break;
for(int i = ; i < H; i ++){
for(int j = ; j < W; j ++){
scanf("%d", &g[i][j]);
}
}
solve();
}
return ;
}