题目描述:点击打开链接
/*
translation:
题目给出冰壶初始位置,以及目标位置。要求以最短的步数将冰壶移动到目标位置。
注意冰壶每往一个方向走上一步,就将一直往这个方向移动知道碰上障碍。碰到障碍
时,障碍本身也被击碎。求出最短的步数是多少??
solution:
dfs,回溯,剪枝
要求最短路径的第一反映是用bfs,但这道题用dfs + 剪枝也能求出来。因为是求最优
解,所以每次找到一个解时就必须对全局变量ans进行更新。所以很自然这道题便采用void
类型的dfs。另外由于步数大于10就必须退出(因为大于10的步数在题目中是非法的),
所以这道题用void类型的dfs就不存在死循环爆栈的问题。
note:
1:void类型的dfs一旦处理不好边会陷入死循环导致爆栈。所以什么时候要return一定
要处理好。此题由于步数不能大于10这个限制条件的存在,所以肯定不会死循环!
2:冰壶移动时一定是向空位移动的,碰到障碍停下同时障碍被击碎。但是冰壶的前进方向
的下一步是障碍时冰壶便不能往这个方向移动。
*/
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn = 25;
const int INF = 1<<30;
const int E = 0;
const int S = 1;
const int W = 2;
const int N = 3;
int w, h, G[maxn][maxn];
int ans;
int dirx[] = {0, 1, 0, -1};
int diry[] = {1, 0, -1, 0};
int start_row, start_col;
int end_row, end_col;
inline bool inside(int r, int c) {
return r >= 0 && r < h && c >= 0 && c < w;
}
void dfs(int row, int col, int cnt) {
if(cnt > 10) return; //note
int tr, tc;
for(int d = 0; d < 4; d++) {
tr = row; tc = col;
if(G[tr + dirx[d]][tc + diry[d]] == 1) continue; //note
bool flag = true;
for(;;) {
tr += dirx[d]; tc += diry[d];
if(!inside(tr, tc)) { flag = false; break; }
if(G[tr][tc] == 1) break;
if(G[tr][tc] == 3) {
ans = min(ans, cnt + 1);
return;
}
}
if(!flag) continue;
G[tr][tc] = 0; //击碎障碍
dfs(tr - dirx[d], tc - diry[d], cnt + 1);
G[tr][tc] = 1;
}
}
int main()
{
//freopen("in.txt", "r", stdin);
while(~scanf("%d%d", &w, &h) && w && h) {
for(int i = 0; i < h; i++) {
for(int j = 0; j < w; j++) {
scanf("%d", &G[i][j]);
if(G[i][j] == 2) {
start_row = i; start_col = j;
}
if(G[i][j] == 3) {
end_row = i; end_col = j; //start position & end position
}
}
}
ans = INF;
dfs(start_row, start_col, 0);
if(ans > 10) printf("-1\n");
else printf("%d\n", ans);
}
return 0;
}