HDU1072 Nightmare (搜索算法)(DFS or BFS)


这道题是 搜索算法 dfs 或者bfs  

悲催的路啊 !

Nightmare

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


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


尴尬的题目   题目的大体意思 就是   从2  出发  0 代表墙 1 代表 路 4代表炸弹重置点  每走一步炸弹时间减少, 走的时间增加   炸弹初始时间为6 

  目的地3   就是是个 迷宫问题 搜索算法 dfs  或者 bfs 

但是dfs 要注意剪枝   负责会 造成 超内存   dfs   提交了 30多次  直接醉了 


#include<stdio.h>
#include<string.h>
#include<stdlib.h>


int n,m,si,sj;
int map[9][9];
int ttime[9][9],step[9][9];
int ans;
int dir[4][2]={{1,0},{-1,0},{0,1},{0,-1}};

void dfs(int x,int y,int temptime,int bombtime)
{
	if(bombtime<=0||temptime>=ans)return;
	
	if(map[x][y]==3)
	{
		if(temptime<ans)
			ans=temptime;
		return;
	}
	if(map[x][y]==4)//时间重置 
	{
		bombtime=6;
	}
	//printf("%d\n",map[x][y]);
	if(temptime>=step[x][y] && ttime[x][y]>=bombtime)
		return;//优化操作  如果现在的时间比 
	//上次大 并且炸弹时间小
				//  直接 不在往下走 剪枝掉 
	//没有这个操作   就会超出内存  
	step[x][y]=temptime;
	ttime[x][y]=bombtime;
	for(int i=0;i<4;i++)
	{
		int px=x+dir[i][0];
		int py=y+dir[i][1];
	
		if(map[px][py]!=0&&x>=0&&y>=0&&y<m&&x<n)//不越界 不是墙 
			dfs(px,py,temptime+1,bombtime-1);// 炸弹时间 减一  走的步骤时间  加一 
	}
}
int main()
{
	int t,i,j;
	scanf("%d",&t);
	while(t--)
	{
		memset(map,0,sizeof(map));
		memset(step,0,sizeof(step));
		memset(ttime,0,sizeof(ttime));
		scanf("%d %d",&n,&m);
		for(i=0;i<n;i++)
		{
			for(j=0;j<m;j++)
			{
				ttime[i][j]=0;
				step[i][j]=1000;//这里置一个大数,表示到i,j的步数无限大
				scanf("%d",&map[i][j]);
				if(map[i][j]==2)
				{
					si = i;
					sj = j;
				}
				
			}
		}
	
		ans = INT_MAX;
		dfs(si,sj,0,6);
		if(ans==INT_MAX)
			printf("-1\n");
		else
			printf("%d\n",ans);
	}
	return 0;
}


/*
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 
*/

这个 第一个测试数据 也是醉了   在我的电脑上 输出2   提交 竟然对了  在win7上  竟然就是4   尴尬- -  


23

下面是bfs    bfs 不同于dfs  不需要保留ans  比较大小  bfs 只要搜索完成并且找到结果 结果就是 最小   BFS 用到queue 队列 套用模板  就这个题而言 不需要 设置vis 访问 因为 是可以往回走的 。 但是 注意 剪枝问题  即在 炸弹重置点 直走一次!  所以走过后 赖皮一下 

将 炸弹重置点 变成0 此题0 是墙   就不让他走了。

#include<iostream> 
#include<queue>
#include<string>

using namespace std;

int map[9][9];
int n,m,si,sj;
int ans;
int dir[4][2]={0,1,0,-1,1,0,-1,0};
struct Node{
	int x;
	int y;
	int time,bomb;
};
int bfs(int x,int y)
{
	int i;
	queue<Node> Q;
	Node now,next;
	now.x=x;
	now.y=y;
	now.bomb=6;
	now.time=0;
	Q.push(now);// 压入队列  初始化   
	while(!Q.empty())
	{
		now=Q.front();//下一次 取出头 
		Q.pop();// 释放 
		
//		if(now.bomb<=0) continue; //炸弹爆炸  
		
		for(i=0;i<4;i++)
		{//4 个方向 
			next.x=now.x+dir[i][0];
			next.y=now.y+dir[i][1];
			next.time=now.time+1;//走的时间变化  
			next.bomb=now.bomb-1;//炸弹时间变化 
			if(next.x>=0&&next.x<n&&next.y>=0&&next.y<m)//不越界 非墙 
			{
				if(map[next.x][next.y]!=0&&next.bomb>0) 
				{
					//非墙, 炸弹时间还有   

					if(map[next.x][next.y]==3)//如果 到达目的 反回时间 
					{
						return next.time;
					}
					if(map[next.x][next.y]==4) //重置 
					{
						next.bomb=6;
						map[next.x][next.y]=0;//设置一下 走过后不在走 回来  变成墙 
					}
					Q.push(next);
				}
			}
		}
	}
	return -1;//出不去  没有结果 或者炸弹炸了
}
int main()
{
	int T,i,j;
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d %d",&n,&m);
		for(i=0;i<n;i++)
			for(j=0;j<m;j++)
			{
				scanf("%d",map[i]+j);
				if(map[i][j]==2)
				{
					si=i;sj=j;
				}
			}
		ans=bfs(si,sj);
		printf("%d\n",ans);
	}
	return 0;
	
}
/*
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 
*/

posted @ 2017-03-01 20:39  Sizaif  阅读(166)  评论(0编辑  收藏  举报