题目中描述的是走过的路径还可以重新再走,也就是说走过的路径不需要标记。但是当遇到重设爆炸时间的点需要标记,不能再从这里经过。如果遇到爆炸点不标记的话,那么这个点就可以无限次数的走,剩余时间会被重设为6,那么剩余时间永远都不会消耗完,那么这个程序也就成了一个死循环。
#include <queue>
#include <string.h>
#include <iostream>
using namespace std;
#define MAXN 10
//定义方向,顶部开始,顺时针
int dir[4][2] = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}};
int n, m;
int a[MAXN][MAXN];
int vis[MAXN][MAXN];
int startX, startY; //开始位置
int endX, endY; //结束位置
struct Node
{
int x;
int y;
int leftTime; //剩余时间
int cnt; //走到当前位置共走了多少步
}now, nextStep;
//判断结点能否通过
bool isPracticable(Node node)
{
//当超出边界,或者剩余时间为0,或者遇到障碍物都不能再通过
if (node.x < 0 || node.x > n || node.y < 0 || node.y > m || node.leftTime <= 0 || a[node.x][node.y] == 0 || vis[node.x][node.y]) {
return 0;
}
return 1;
}
int BFS()
{
memset(vis, 0, sizeof(vis));
queue<Node> Q;
now.x = startX;
now.y = startY;
now.leftTime = 6;
now.cnt = 0;
Q.push(now);
while (!Q.empty()) {
//获取队列首部元素
now = Q.front();
if (now.x == endX && now.y == endY) {
return now.cnt;
}
for (int i = 0; i < 4; i++) { //按照上、右、下、左的方向搜索,搜索方向可随意,但是要保证四个方向都被搜索一遍
nextStep.x = now.x + dir[i][0];
nextStep.y = now.y + dir[i][1];
nextStep.cnt = now.cnt + 1;
nextStep.leftTime = now.leftTime - 1;
if (isPracticable(nextStep)) {
if (a[nextStep.x][nextStep.y] == 4) {
nextStep.leftTime = 6; //当走到重设爆炸时间点的时候,把剩余时间重新设置为6
vis[nextStep.x][nextStep.y] = 1; //把能够重新设置爆炸时间的位置标记为1,此处只能走一次
}
Q.push(nextStep);
}
}
//把对首元素排出队列
Q.pop();
}
return -1;
}
int main(int argc, const char * argv[]) {
int T;
cin >> T;
while (T--) {
cin >> n >> m;
memset(a, 0, sizeof(a));
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
cin >> a[i][j];
if (a[i][j] == 2) { //记录开始点
startX = i;
startY = j;
} else if (a[i][j] == 3) { //记住结束点
endX = i;
endY = j;
}
}
}
cout << BFS() << endl;
}
return 0;
}