题目链接:
https://vjudge.net/problem/POJ-3009
题目大意:
问题:打冰球。冰球可以往上下左右4个方向走,只有当冰球撞到墙时才会停下来,而墙会消失。当冰球紧贴墙时,不能将冰球往那个方向打。冰球出界就当输,超过10次还没将冰球打到目标位置也当输。求用最小次数将冰球打到目标位置,或输出-1表示输了。
思路:
分析:一般来说,求最小步数之类的迷宫问题都是用BFS解决的,但这题涉及到迷宫状态的变化(墙),BFS要不断记录状态的变化很复杂,不过网上好像也有人用BFS做的。DFS更加适合这种状态一直变化的,只不过要保存最优值而已,其实最优值也方便剪枝(当前步数已经是当前最优值大小但还没到达目的地也就没必要进行下去了)。需要注意的是,这题并不是移动一格,而是一直移动直到遇到障碍物。特别是目标点可能在移动的过程中到达。具体看代码。
1 #include<iostream> 2 #include<vector> 3 #include<queue> 4 #include<algorithm> 5 #include<cstring> 6 #include<cstdio> 7 #include<set> 8 #include<map> 9 #include<cmath> 10 using namespace std; 11 typedef pair<int, int> Pair; 12 typedef long long ll; 13 const int INF = 0x3f3f3f3f; 14 int T, n, m, d; 15 const int maxn = 1e5 + 10; 16 int Map[150][150], ans;//Map[i][j]表示ij这个点的最短 17 int dir[4][2] = {1,0,0,1,-1,0,0,-1}; 18 bool judge(int x, int y) 19 { 20 return (x >= 0 && x < n && y >= 0 && y < m); 21 } 22 void dfs(int x, int y, int d) 23 { 24 if(Map[x][y] == 3) 25 { 26 ans = min(ans, d); 27 return; 28 } 29 if(d >= 10)return; 30 for(int i = 0; i < 4; i++) 31 { 32 int xx = x + dir[i][0]; 33 int yy = y + dir[i][1]; 34 if(!judge(xx, yy) || Map[xx][yy] == 1)continue; 35 while(1) 36 { 37 if(!judge(xx, yy))break; 38 if(Map[xx][yy] == 1) 39 { 40 Map[xx][yy] = 0; 41 dfs(xx-dir[i][0], yy-dir[i][1], d + 1); 42 Map[xx][yy] = 1; 43 break; 44 } 45 else if(Map[xx][yy] == 3) 46 { 47 dfs(xx, yy, d + 1); 48 break; 49 } 50 xx += dir[i][0]; 51 yy += dir[i][1]; 52 } 53 } 54 } 55 int main() 56 { 57 while(cin >> m >> n && (n + m)) 58 { 59 int sx, sy; 60 for(int i = 0; i < n; i++) 61 for(int j = 0; j < m; j++) 62 { 63 cin >> Map[i][j]; 64 if(Map[i][j] == 2) 65 sx = i, sy = j, Map[i][j] = 0; 66 } 67 ans = INF; 68 dfs(sx, sy, 0); 69 if(ans > 10)cout<<"-1"<<endl; 70 else cout<<ans<<endl; 71 } 72 return 0; 73 }