题目链接
题目大意:
可以视为一个迷宫问题,从四个方向中选取一个方向一直走,直到撞到墙或者经过出口(此时无需停止,即只需路过出口)时停止,如果是碰到了墙壁,那么停止之后这一块墙壁也消失,自身则停在与墙壁相撞的位置。并且地图是有限制的,如果直走的时候没有经过出口而直接走出了地图,也认为失败。求出改变方向的最小次数,如果超过10,也认为失败。
下图是一个走迷宫的示例以及经过墙壁的消失之后最终的迷宫形状:
Sample Input
2 1
3 2
6 6
1 0 0 2 1 0
1 1 0 0 0 0
0 0 0 0 0 3
0 0 0 0 0 0
1 0 0 0 0 1
0 1 1 1 1 1
6 1
1 1 2 1 1 3
6 1
1 0 2 1 1 3
12 1
2 0 1 1 1 1 1 1 1 1 1 3
13 1
2 0 1 1 1 1 1 1 1 1 1 1 3
0 0
Sample Output
1
4
-1
4
10
-1
解题思路:
最开始看到“最小”字眼,考虑使用BFS进行搜索,但是不同的方向会使不同的墙壁消失,子问题的搜索空间不一致。因此还是使用了DFS,使用一个全局变量来保存最小的改变方向次数。记得回溯的时候要将被消除的墙进行还原。
代码:
#include<iostream>
#include<algorithm>
#include<math.h>
using namespace std;
int n, m;
int mynext[4][2] = { 1,0,-1,0,0,1,0,-1 };
int sx, sy;
int map[21][21];
#define INF 0x3fffffff
int ans;
bool ans_Flag;//用于判断是否存在有效答案(即不超过10步的答案)
void DFS(int x, int y, int now) {
if (now > 10) { return; }
for (int i = 0; i < 4; i++) {
int nx = x + mynext[i][0];
int ny = y + mynext[i][1];
if (nx >= n||nx < 0 || ny >= m||ny < 0 || map[nx][ny] == 1) { continue; }
int flag = 0;
while (nx < n&&nx >= 0 && ny < m&&ny >= 0 ) {
if (map[nx][ny] == 1) { flag = 1; break; }//正常退出
if (map[nx][ny] == 3) {
if (now + 1 > 10) { return; }//提前剪枝
ans_Flag = true;
ans = min(ans, now + 1);
return;
}
nx += mynext[i][0];
ny += mynext[i][1];
}
if (flag == 0) { continue; }//非正常退出则尝试下一个方向
map[nx][ny] = 0;//消除墙壁
DFS(nx - mynext[i][0], ny - mynext[i][1], now + 1);
map[nx][ny] = 1;//还原墙壁
}
}
int main() {
while (cin >> m >> n) {
if (m == 0 && n == 0) { break; }
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
cin >> map[i][j];
if (map[i][j] == 2) { sx = i; sy = j; }
}
}
ans = INF;
ans_Flag = false;
DFS(sx, sy, 0);
if (ans_Flag) { cout << ans << endl; }
else cout << -1 << endl;
}
//system("pause");
return 0;
}