HDU 1072 Nighmare 【BFS】



Nightmare

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 6419    Accepted Submission(s): 3124


Problem Description
Ignatius had a nightmare last night. He found himself in a labyrinth with a time bomb on him. The labyrinth has an exit, Ignatius should get out of the labyrinth before the bomb explodes. The initial exploding time of the bomb is set to 6 minutes. To prevent the bomb from exploding by shake, Ignatius had to move slowly, that is to move from one area to the nearest area(that is, if Ignatius stands on (x,y) now, he could only on (x+1,y), (x-1,y), (x,y+1), or (x,y-1) in the next minute) takes him 1 minute. Some area in the labyrinth contains a Bomb-Reset-Equipment. They could reset the exploding time to 6 minutes.

Given the layout of the labyrinth and Ignatius' start position, please tell Ignatius whether he could get out of the labyrinth, if he could, output the minimum time that he has to use to find the exit of the labyrinth, else output -1.

Here are some rules:
1. We can assume the labyrinth is a 2 array.
2. Each minute, Ignatius could only get to one of the nearest area, and he should not walk out of the border, of course he could not walk on a wall, too.
3. If Ignatius get to the exit when the exploding time turns to 0, he can't get out of the labyrinth.
4. If Ignatius get to the area which contains Bomb-Rest-Equipment when the exploding time turns to 0, he can't use the equipment to reset the bomb.
5. A Bomb-Reset-Equipment can be used as many times as you wish, if it is needed, Ignatius can get to any areas in the labyrinth as many times as you wish.
6. The time to reset the exploding time can be ignore, in other words, if Ignatius get to an area which contain Bomb-Rest-Equipment, and the exploding time is larger than 0, the exploding time would be reset to 6.
 

Input
The input contains several test cases. The first line of the input is a single integer T which is the number of test cases. T test cases follow.
Each test case starts with two integers N and M(1<=N,Mm=8) which indicate the size of the labyrinth. Then N lines follow, each line contains M integers. The array indicates the layout of the labyrinth.
There are five integers which indicate the different type of area in the labyrinth:
0: The area is a wall, Ignatius should not walk on it.
1: The area contains nothing, Ignatius can walk on it.
2: Ignatius' start position, Ignatius starts his escape from this position.
3: The exit of the labyrinth, Ignatius' target position.
4: The area contains a Bomb-Reset-Equipment, Ignatius can delay the exploding time by walking to these areas.
 

Output
For each test case, if Ignatius can get out of the labyrinth, you should output the minimum time he needs, else you should just output -1.
 

Sample Input
 
  
3 3 3 2 1 1 1 1 0 1 1 3 4 8 2 1 1 0 1 1 1 0 1 0 4 1 1 0 4 1 1 0 0 0 0 0 0 1 1 1 1 4 1 1 1 3 5 8 1 2 1 1 1 1 1 4 1 0 0 0 1 0 0 1 1 4 1 0 1 1 0 1 1 0 0 0 0 3 0 1 1 1 4 1 1 1 1 1
 

Sample Output
 
  
4 -1 13
 

题意:

一张地图中,1,2,3,4都可以走,0不能走,一个人有6分钟的行走时间,每走一格花费一分钟,如果经过4,能重置行走时间,即又拥有6分钟行走时间,当时间==0的时候,无论有没有到达目的地或者 4这个重置时间的地方,都记为失败,3为目的地的位置;

思路:BFS,,,这里有一个条件,就是地图中除0外的地方可以多次走,最初的做法是用了BFS反复调用,但是会出现内存超限的情况,这里的关键就是用一个mark来标记可以走的领域,这里最棘手的地方就是,当你走进4的时候,那就相当于4为起点可以走之前走过的路径,但是传统的BFS每次经过都会给走过的地方做标记,防止重复走,这里需要把这个标记的mark做些调整,无论是起点还是走到4这个位置,你能走的步数始终都只有6步,事实上是5步,我们可以每走一个地方,给所在位置mark【】【】存入当前所剩时间,然后每走一步,需要判断的不再是这个地方有没有走过,而是这个地方过去走过的所剩时间和当前的比较,如果当前的所剩时间比过去走过所剩时间大,那么这个地方就可以走,从而解决,走过的路径重复走这个棘手的问题,因为你不可能不去标记过去走过的地方,这样BFS会无限下去,是不会有输出的;下面给出代码:



#include<iostream>
#include<string>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<time.h>
#include<algorithm>
#include<cmath>
#include<stack>
#include<list>
#include<queue>
#include<map>

#define E exp(1)
#define PI acos(-1)
#define mod (ll)(1e9+9)
#define INF 0x3f3f3f3f;
#define MAX 40000
#define compare 0.00000001
#define exps 1e-8
#define fr_add(i,init,n) for(int i = init ; i < n ; ++i)
#define fr_div(i,init,n) for(int i = n ; i >= init ; --i)

//#define _CRT_SECURE_NO_WARNINGS
//#define LOCAL
using namespace std;

typedef long long ll;
typedef long double lb;

int dir[4][2] = { { -1,0 },{ 1,0 },{ 0,-1 },{ 0,1 } }; //方向
int n, m, mark[9][9];
int mp[9][9];  //地图
struct point {
	int x, y, step, time;
};

struct point start;

int bfs(struct point tp) {
	queue<struct point> qu;
	struct point temp, Front;
	mark[tp.x][tp.y] = 6;
	qu.push(tp);
	while (!qu.empty()) {
		Front = qu.front();
		qu.pop();

		if (mp[Front.x][Front.y] == 3) {
			return Front.step;
		}

		fr_add(i, 0, 4) {
			temp.x = Front.x + dir[i][0]; temp.y = Front.y + dir[i][1];
			temp.step = Front.step + 1; temp.time = Front.time - 1;
			//注意下面if的条件,第一是坐标超出范围的情况排除掉
			//第二个是mark的判断,看看能不能走这个地方,然后就是一个时间time,和mp是不是为0的情况
			if (temp.x >= 0 && temp.x < n&&temp.y >= 0 && temp.y < m&&
				mark[temp.x][temp.y] < mark[Front.x][Front.y] && mp[temp.x][temp.y] != 0&&temp.time>0) {
				//如果mp==4 那么时间重置为6
				if (mp[temp.x][temp.y] == 4) temp.time = 6;

				mark[temp.x][temp.y] = temp.time;
				qu.push(temp);

			}
		}
	}
	return -1;
}

int main(void)
{
#ifdef LOCAL
	freopen("data.in.txt", "r", stdin);
	freopen("data.out.txt", "w", stdout);
#endif
	//ios::sync_with_stdio(false); cin.tie(0);
	int t;
	while (scanf("%d", &t) != EOF) {
		while (t--) {
			scanf("%d%d", &n, &m);

			fr_add(i, 0, n) {
				fr_add(j, 0, m) {
					scanf("%d", &mp[i][j]);
					//找出起点位置坐标
					if (mp[i][j] == 2) {
						start.x = i; start.y = j; start.step = 0; start.time = 6;
					}
				}
			}
			memset(mark, 0, sizeof(mark));
			int res = bfs(start);
			printf("%d\n", res);
		}
	}
	//	end = clock();
	//	cout << "using tmie:" << (double)(end - start) / CLOCKS_PER_SEC * (1000) << "ms" << endl;
	//system("pause");
	return 0;
}








猜你喜欢

转载自blog.csdn.net/godleaf/article/details/80270779