题目链接:https://vjudge.net/problem/POJ-3009
转载于:https://blog.csdn.net/angon823/article/details/49910109
题目大意:
要求把一个冰壶从起点“2”用最少的步数移动到终点“3”,其中0为移动区域,1为石头区域,冰壶一旦想着某个方向运动就不会停止,也不会改变方向(想想冰壶在冰上滑动),除非冰壶撞到石头1 或者 到达终点 3
需要注意的是:
冰壶撞到石头后,冰壶会停在石头前面,此时(静止状态)才允许改变冰壶的运动方向,而该块石头会破裂,石头所在的区域由1变为0. 也就是说,冰壶撞到石头后,并不会取代石头的位置。
终点是一个摩擦力很大的区域,冰壶若到达终点3,就会停止在终点的位置不再移动。并且,如果步数>1,则直接算失败,这条dfs搜索路径直接舍弃。
解题分析:
这里用了dfs来求最小步数,求出所有能够到终点的解,然后用它们不断去更新步数的最小解。下列代码中,用whlie循环来代替它向一个方向走的不同步数,如果能够向前滑行,则while循环继续执行。
#include <iostream> #include <stdio.h> #include <string.h> #include <algorithm> using namespace std; int map[25][25], m, n, sx, sy; int dir[][2] = { 1,0,-1,0,0,1,0,-1 }; int ans; void dfs(int x, int y, int step) { int nx, ny, ex, ey; //(nx,ny) 代表下一步 (ex,ey) 代表走的这一步 if (step>10)return; //实际上是剪枝 for (int i = 0; i<4; i++) //向四个方向走 { nx = x + dir[i][0]; //下一步 ny = y + dir[i][1]; ex = x;ey = y; while (nx >= 0 && nx<m && ny >= 0 && ny<n && map[nx][ny] != 1) //为真则代表这个方向能走,因为冰球紧贴冰块的那个方向不能走 { ex += dir[i][0]; //则走这一步 ey += dir[i][1]; if (map[ex][ey] == 3) //走的这步是终点吗。 { ans = min(ans, step); return; } nx = ex + dir[i][0]; //走完这一步的下一步 ny = ey + dir[i][1]; if (nx<0 || nx >= m || ny<0 || ny >= n) break; //如果下一步是越界,说明会直接滑出去,不必再进行dfs if (map[nx][ny] == 1) //如果下一步是1,进行深搜. { map[nx][ny] = 0; dfs(ex, ey, step + 1); map[nx][ny] = 1; } //如果下一步还是0,按照题意,当然要继续滑下去,继续while,循环前进 } } } int main() { while (~scanf("%d %d", &n, &m), m || n) { for (int i = 0; i<m; i++) for (int j = 0; j<n; j++) { scanf("%d", &map[i][j]); if (map[i][j] == 2) { sx = i; sy = j; } } ans = 0x3f3f3f3f; dfs(sx, sy, 1); if (ans == 0x3f3f3f3f) printf("-1\n"); else printf("%d\n", ans); } return 0; }
2018-05-27