杭电1072————搜索之广搜+结构体的前驱应用

Nightmare

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


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
这个题目看起来和平常的广搜一样没有什么特别之处,但是其中有一句话特别重要也让我一开始非常的纠结
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.
炸弹重置装置可以让你想用多少次就用多少次,而且所有地方都是想走几次就走几次。
这和以前的”迷宫“问题不一样,以前的迷宫每一个坐标只能经过一次,所以我们设立一个vis[x][y]数组标记(x,y)是否走过,这也是我们搜索过程中一个重要的判断条件。但是这道题目将这个限制移除了,那么岂不是会一直循环不断的搜索吗?
其实有一个”隐藏“的条件,题目要求最少的时间,那么所有炸弹重置装置 最多 只能被开启一次。
(假设这个炸弹装置又被开启,说明走了回头路,这样时间肯定不是最少的)
这个问题我一直没有想到......说明智商还是太拙计........
还有关于bombtime,我一开始设定了一个全局变量bombtime,想每次走一步就-1,但是要记得搜索是试探性的,就是你入队的结点有很多,bombtime被减了很多次,但是你需要的结点只有一个,你只想减一次,可以看出这个bombtime和它的前驱是有密切关系的(具体可以看代码)
代码附上:
(杭电亲测0MS...数据量太小。不过如果很大的话肯定超时..没有vis[x][y]的限制的话一个坐标(x,y)肯定会被大量访问,花费时间比较多)
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <queue>
#define maxn 10
using namespace std;
struct node{
	int x,y,bombtime,time;
};
int dx[4] = {1,-1,0,0},dy[4] = {0,0,1,-1};/*diretions*/
int maze[maxn][maxn];
int sx,sy;/*start_x,start_y,end_x,end_y*/
int row,colum;

queue<node> Q;
 
void read()
{
	for(int i = 0 ; i < row ; i++)
	{
		for(int j = 0 ; j < colum ; j++)
		{
			scanf("%d",&maze[i][j]);
			if(maze[i][j] == 2){
				sx = i;
				sy = j;
			}
		}
	}
}
int check(int x,int y)
{
	int flag = 1;
	
	if(x < 0 || x > row - 1 || y < 0 || y > colum - 1)
		flag = 0;
	if(maze[x][y] == 0)
		flag = 0;
	return flag;
}
void BFS()
{
	struct node now,next;
	
	while(!Q.empty())
		Q.pop();/*搜索时先清空队列*/
	now.x = sx;
	now.y = sy;
	now.time = 0;
	now.bombtime = 6;
	Q.push(now);
	while(!Q.empty())
	{
		now = Q.front();
		Q.pop();
		for(int k = 0 ; k < 4 ; k++)
		{
			next.x = now.x + dx[k];
			next.y = now.y + dy[k];
			if(check(next.x,next.y) && now.bombtime-1 > 0)
			{
				next.bombtime = now.bombtime - 1;
				if(maze[next.x][next.y] == 4)
				{
					next.bombtime = 6;
					maze[next.x][next.y] = 0;/*重置器可以被二次使用,但是一旦被二次使用肯定不是最短时间*/ 
				}
				next.time = now.time + 1;
				Q.push(next);
				if(maze[next.x][next.y] == 3)
				{
					printf("%d\n",next.time);
					return ;
				}
			}
		}
	}
	printf("%d\n",-1);
}
int main()
{
	int cases;
	
	scanf("%d",&cases);
	while(cases--)
	{
		memset(maze,0,sizeof(maze));/*0表示不能通过*/
		scanf("%d%d",&row,&colum);
		read();/*已测试*/ 
		BFS();
	}
	return 0;
}

PS:从这个题目里边我还是学到不少东西的,最最起码加深了我对结构体”前驱元素“的怨念,深深的了解了它的重要性.....还有自己的智商实在拙计


posted @ 2014-07-30 20:48  SixDayCoder  阅读(233)  评论(0编辑  收藏  举报