dfs+优先队列(poj2312)

本文介绍了如何利用改进的BFS和优先队列解决一个坦克游戏的路径规划问题。坦克从起点到目的地需要避开障碍并可能需要破坏砖墙,目标是最短时间到达。文章提供了两种方法:1) 通过BFS并在遇到砖墙时停顿一步;2) 使用优先队列,每次出队时选择时间值最小的节点。
摘要由CSDN通过智能技术生成
Battle City
Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 9482   Accepted: 3134

Description

Many of us had played the game "Battle city" in our childhood, and some people (like me) even often play it on computer now. 

What we are discussing is a simple edition of this game. Given a map that consists of empty spaces, rivers, steel walls and brick walls only. Your task is to get a bonus as soon as possible suppose that no enemies will disturb you (See the following picture). 

Your tank can't move through rivers or walls, but it can destroy brick walls by shooting. A brick wall will be turned into empty spaces when you hit it, however, if your shot hit a steel wall, there will be no damage to the wall. In each of your turns, you can choose to move to a neighboring (4 directions, not 8) empty space, or shoot in one of the four directions without a move. The shot will go ahead in that direction, until it go out of the map or hit a wall. If the shot hits a brick wall, the wall will disappear (i.e., in this turn). Well, given the description of a map, the positions of your tank and the target, how many turns will you take at least to arrive there?

Input

The input consists of several test cases. The first line of each test case contains two integers M and N (2 <= M, N <= 300). Each of the following M lines contains N uppercase letters, each of which is one of 'Y' (you), 'T' (target), 'S' (steel wall), 'B' (brick wall), 'R' (river) and 'E' (empty space). Both 'Y' and 'T' appear only once. A test case of M = N = 0 indicates the end of input, and should not be processed.

Output

For each test case, please output the turns you take at least in a separate line. If you can't arrive at the target, output "-1" instead.

Sample Input

3 4
YBEB
EERE
SSTE
0 0

Sample Output

8

#include<iostream>
#include<queue>
#include<cstring>
using namespace std;
char map[305][305];
bool visit[305][305];
int dx[4]={1,-1,0,0},dy[4]={0,0,1,-1};
int m,n,sx,sy,ex,ey;
struct node
{
	int x,y,time;
};
bool operator < (node a,node b)//优先队列中元素的默认比较规则是按元素的值从大到小排序,
                         //取栈顶元素为最大,所以需函数重载 
{
	return a.time>b.time;//从小到大排序采用">",从大到小排序采用"<" 
}
bool ok(int x,int y)
{
	if(x>=0&&x<m&&y>=0&&y<n&&map[x][y]!='S'&&map[x][y]!='R') return true;
	else return false;
}
int bfs()
{
	priority_queue<node> q;//优先队列每部取最小操作次数继续走 
	memset(visit,false,sizeof(visit));
	visit[sx][sy]=true;
	node start={sx,sy,0};
	q.push(start);
	while(!q.empty())
	{
		node s=q.top();
		q.pop();
		if(s.x==ex&&s.y==ey) return s.time;//到达目的地 
		for(int i=0;i<4;i++)
		{
			int xx=s.x+dx[i],yy=s.y+dy[i];//搜索下一个点 
			if(ok(xx,yy)&&!visit[xx][yy])//判断下一个点是否合法 
			{
				visit[xx][yy]=true;//标记已经走过的点 
				int t=0;
				if(map[xx][yy]=='B') t=2;
				else  t=1;
				node next={xx,yy,s.time+t};
				q.push(next);
			}
		}
	}
	return -1;
}
int main()
{
	while(cin>>m>>n&&(m||n))
	{
		for(int i=0;i<m;i++)
		    for(int j=0;j<n;j++)
			{
			    cin>>map[i][j];
			    if(map[i][j]=='Y')//记录起始点 
			    {
			    	sx=i;sy=j;	
				}
				else if(map[i][j]=='T')//终点 
				{
					ex=i;ey=j;
				}
		    }
		cout<<bfs()<<endl;
	}
	return 0;
}

参考:

相信坦克大战大家都玩过吧,本题就是根据这个游戏设计的。坦克要从起点(Y),到目的地(T),坦克不能通过钢墙(S),河(R),可以在空地在行走(E),射击破坏砖墙(B),射击砖墙时不行走且花费一个单位的时间,在空地上行走时也花费一个单位的时间。求坦克从起点到目的地最少花多少时间,不可达输出-1;

很好的一道搜索题。因为考虑到通过砖墙时和空地所花的时间不同,所以不能使用一般的BFS广搜来做。用DFS深搜,你会发现时间复杂非常高,必然会超时(最大是300*300的图)。本题可以使用改进过的广搜或优先队列+bfs 或 记忆化广搜三种方法来解决。

第一种方法:改进过的BFS:

有些节点需要耗费2个单位时间,要想用BFS就得改一下,由于BFS每次只能操作一步,要不就是扩展,要不就是破坏砖墙。所以只需检查该点是不是'B',是的话就得停一步,不是的话,继续扩展,也就是说某些点的扩展慢了一拍,所以从队列里出来的点就判断一下再看执行哪个操作。

从这道题,我也对bfs有了更深的理解,“bfs之所以能最快找到最优解,就是因为它每次操作一步(这里的操作一步,很灵活,例如题目中的破坏砖墙),而while()里面的语句就是一次操作了!”

Cpp代码 
  1. /* 
  2. 这道题中B点需要操作两步,所以遇到B点后不能+2后直接压进队列,需要在原地停一下,不能扩展到其他点,相当于他只能扩展到自身,所以就把自身压进队列里map[x][y]='E'是因为破坏砖墙一次就够了,不然下次,还是'B',不断压进队列,不断在原地停留 
  3. 平常一般是考虑“入队列” 的点,这次要考虑“出队列” 的点是否满足条件! 
  4. */  
  5. #include "iostream"  
  6. #include "queue"  
  7. using namespace std;  
  8.   
  9. char map[301][301];  
  10. bool visit[301][301];  
  11. int dir[4][2]={ {1,0},{-1,0},{0,1},{0,-1}};  
  12. int m,n,sx,sy;  
  13.   
  14. struct node  
  15. {  
  16.     int x,y,time;  
  17. };  
  18. int bfs()  
  19. {  
  20.     int i;  
  21.     node you,start,next;  
  22.     queue<node>q;  
  23.     you.x=sx;  
  24.     you.y=sy;  
  25.     you.time=0;  
  26.   
  27.     q.push(you);  
  28.     visit[sx][sy]=1;  
  29.   
  30.     while(!q.empty())  
  31.     {  
  32.         start=q.front();  
  33.         q.pop();  
  34.         if(map[start.x][start.y]=='B')  //这一步需要停一停  
  35.         {  
  36.             start.time++;  
  37.             map[start.x][start.y]='E';  
  38.             q.pus
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值