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?
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()里面的语句就是一次操作了!”
- /*
- 这道题中B点需要操作两步,所以遇到B点后不能+2后直接压进队列,需要在原地停一下,不能扩展到其他点,相当于他只能扩展到自身,所以就把自身压进队列里map[x][y]='E'是因为破坏砖墙一次就够了,不然下次,还是'B',不断压进队列,不断在原地停留
- 平常一般是考虑“入队列” 的点,这次要考虑“出队列” 的点是否满足条件!
- */
- #include "iostream"
- #include "queue"
- using namespace std;
- char map[301][301];
- bool visit[301][301];
- int dir[4][2]={ {1,0},{-1,0},{0,1},{0,-1}};
- int m,n,sx,sy;
- struct node
- {
- int x,y,time;
- };
- int bfs()
- {
- int i;
- node you,start,next;
- queue<node>q;
- you.x=sx;
- you.y=sy;
- you.time=0;
- q.push(you);
- visit[sx][sy]=1;
- while(!q.empty())
- {
- start=q.front();
- q.pop();
- if(map[start.x][start.y]=='B') //这一步需要停一停
- {
- start.time++;
- map[start.x][start.y]='E';
- q.pus