题目太长就不贴了,题意:
上下左右四联通块,2表示起点,3表示终点,1为block,0为空地,每动一次冰壶,冰壶就会向推动的方向一直移动,直到碰到block或出界,如果碰到block就在block前停下来,同时block消失,如果出界则失败,输出-1,同时,如果在10次推动内都没达到终点也失败,输出-1。如果成功,则输出最少推动次数。
思路:
有四种情况:1,冰壶起点周围没有空地,不能推动,失败; 2,冰壶周围有空地可以移动,则进行对周围进行dfs,情况有三,①直接遇到终点、②碰到block、③出界。
总结:
被这题难住的地方有 :①冰壶可以一直移动,②block会消失,所以如果dfs不成功,还要复原,③对于一开始就不能移动的冰壶做判断。对于第一种情况用一趟while()一直对一个方向更新坐标直到边界条件或下次dfs起点,就解决了;对于第二种情况,可以看下面的AC代码,其实每次冰壶碰到block之后让block消失,然后重新dfs,但在dfs返回时再复原就好了,这时 ans 已经记录下最少移动次数的信息,对于block存不存在对结果没有影响,自己可以思考一下;情形三,则作一判断 !( nx-dir[i][0] == x && ny-dir[i][1] == y ),具体看下面的代码。
当把上面的情况理清之后,就是一道很基础的dfs了~
下面是AC代码:
#include<iostream> #include<cstdio> using namespace std; #define maxn 30 #define INF 9000 int d[4][2] = { 0,1, 0, -1, 1, 0, -1, 0 }; int bo[maxn][maxn]; int w, h, ans; bool check(int a, int b) { if(a >= 0 && b >= 0 && a < h && b < w) return true; return false; } int x; void dfs(int a, int b, int rec) { if(rec > 10 || rec > ans) return; for(int i = 0; i < 4; i++) { int dx = a + d[i][0]; int dy = b + d[i][1]; if(check(dx, dy) && (bo[dx][dy] == 0 || bo[dx][dy] == 2|| bo[dx][dy] == 3)){ bool flag = 0;//cout<<i<<endl; while(bo[dx][dy] != 1 && bo[dx][dy] != 3){ dx += d[i][0]; dy += d[i][1]; if(!check(dx, dy)) { flag = 1; break; } } if(flag) continue; if(bo[dx][dy] == 1) { bo[dx][dy] = 0; dfs(dx-d[i][0], dy-d[i][1], rec+1); bo[dx][dy] = 1; } if(bo[dx][dy] == 3){ if(ans > rec) ans = rec; return; } } } } void work() { int sx, sy; for(int i = 0; i < h; i++){ for(int j = 0; j < w; j++){ scanf("%d", &bo[i][j]); if(bo[i][j] == 2) sx = i, sy = j; } } ans = INF; dfs(sx, sy, 1); if(ans == INF) printf("-1 "); else printf("%d ", ans); } int main() { while(scanf("%d%d", &w, &h) != EOF && h && w){ work(); } return 0; }
作者:u011652573 发表于2014-4-15 22:42:28 原文链接
阅读:61 评论:0 查看评论