题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1072
题目大意:判断是否能走出迷宫,若不能走出,输出-1,若能走出,求走出迷宫的步数?如果没有走到重置的点,一次最多走5步(迷宫中:0表示wall;1表示空白;2表示起点;3表示出口;4表示可以重置步数为6).
题意分析:
1、本题属于常见的搜索题,可采用广度优先搜索。
2、但,本题有一个特殊的地方:当遇到4时,能走的步数重置为6,所以与普通的广度优先有所不同,我们需要设一个mark变量,其size与迷宫一样,用来记录走到迷宫中当前点时的最大剩余步数。
3、在遍历过程中,只有当如果走到某点时的剩余步数大于该点的剩余步数时,该点才进入队列;否则,说明该点已经进入过队列并且再路过该点只会减少剩余步数,故不能进入队列。
#include<stdio.h>
#include<string.h>
#include<queue>
using namespace std;
int labyrinth[9][9];
int mark[9][9];
int dir[4][2] = {{1,0},{0,1},{-1,0},{0,-1}}; //down->right->up->left(counter-clockwise)
int M, N;
int res;
int flag;
typedef struct
{
int y;
int x;
int bombTime;
int totalTime;
}queNode;
queue<queNode> que;
void bfs(int y, int x)
{
int i;
queNode curNode, nextNode;
curNode.y = y;
curNode.x = x;
curNode.bombTime = 6;
curNode.totalTime = 0;
mark[y][x] = 6;
que.push(curNode);
while(!que.empty())
{
curNode = que.front();
que.pop();
for(i=0; i<4; i++)
{
nextNode.y = curNode.y + dir[i][0];
nextNode.x = curNode.x + dir[i][1];
nextNode.bombTime = curNode.bombTime - 1;
nextNode.totalTime = curNode.totalTime + 1;
if(nextNode.y>=N || nextNode.y<0 || nextNode.x>=M || nextNode.x<0)
{
continue;
}
if(nextNode.bombTime >= 1)
{
if(labyrinth[nextNode.y][nextNode.x] == 0)
{
continue;
}
if(labyrinth[nextNode.y][nextNode.x] == 4)
{
nextNode.bombTime = 6;
if(mark[nextNode.y][nextNode.x] < nextNode.bombTime)
{
mark[nextNode.y][nextNode.x] = nextNode.bombTime;
que.push(nextNode);
}
}
else if(labyrinth[nextNode.y][nextNode.x]==3)
{
flag = 1;
res = nextNode.totalTime;
return;
}
else if(labyrinth[nextNode.y][nextNode.x]==1 && mark[nextNode.y][nextNode.x]<nextNode.bombTime)
{
mark[nextNode.y][nextNode.x] = nextNode.bombTime;
que.push(nextNode);
}
}
}
}
}
int main()
{
int i, j;
int T;
int sX, sY; //start place
scanf("%d", &T);
while(T--)
{
scanf("%d%d", &N, &M);
for(i=0; i<N; i++)
{
for(j=0; j<M; j++)
{
scanf("%d", &labyrinth[i][j]);
}
}
for(i=0; i<N; i++)
{
for(j=0; j<M; j++)
{
if(labyrinth[i][j] == 2)
{
sY = i;
sX = j;
break;
}
}
}
flag = 0;
res = 0;
memset(mark, 0, sizeof(mark));
bfs(sY, sX);
while(!que.empty()){
que.pop();
}
if(flag == 1)
{
printf("%d\n", res);
}
else
{
printf("-1\n");
}
}
return 0;
}
//再贴个用dfs的做法,但不知道为什么老wrong answer。。。
#include<stdio.h>
#include<string.h>
int labyrinth[9][9];
int visited[9][9];
int dir[4][2] = {{1,0},{0,1},{-1,0},{0,-1}}; //down->right->up->left(counter-clockwise)
int M, N;
int totalTime, bombTime;
int res;
int flag;
void dfs(int y, int x)
{
int i, nextY, nextX;
int temp;
if(bombTime <= 0){
return;
}
if(flag == 1){
return;
}
printf("%d %d %d %d %d %d\n", y, x, flag, res, bombTime, totalTime);
for(i=0; i<4; i++){
nextY = y + dir[i][0];
nextX = x + dir[i][1];
if(nextY>=N || nextY<0 || nextX>=M || nextX<0){
continue;
}
if(visited[nextY][nextX] < bombTime-1){
if(labyrinth[nextY][nextX]==1){
totalTime++;
bombTime--;
visited[nextY][nextX] = bombTime;
dfs(nextY, nextX);
totalTime--;
bombTime++;
}
else if(labyrinth[nextY][nextX] == 3){ //Find the exit
flag = 1;
totalTime++;
res = totalTime;
return;
}
else if(labyrinth[nextY][nextX]==4){//Go to a reset equipment place
totalTime++;
temp = bombTime;
bombTime = 6;
visited[nextY][nextX] = 6;
dfs(nextY, nextX);
bombTime = temp;
totalTime--;
}
}
}
}
int main()
{
int i, j;
int T;
int sX, sY; //start place
scanf("%d", &T);
while(T--){
scanf("%d%d", &N, &M);
for(i=0; i<N; i++){
for(j=0; j<M; j++){
scanf("%d", &labyrinth[i][j]);
}
}
for(i=0; i<N; i++){
for(j=0; j<M; j++){
if(labyrinth[i][j] == 2){
sY = i;
sX = j;
break;
}
}
}
bombTime = 6;
totalTime = 0;
flag = 0;
res = 0;
memset(visited, 0, sizeof(visited));
visited[sY][sX] = 6;
dfs(sY, sX);
if(flag == 1){
printf("%d\n", res);
}
else{
printf("-1\n");
}
}
return 0;
}