Problem 38: bench与奔驰
Time Limit:1 Ms| Memory Limit:128 MB
Difficulty:2
Description
公园里有个人在练开奔驰 - -!,但是总是撞在bench上 (众人曰:狼来了,快跑啊!)
公园里的bench与奔驰都是无敌的,不会被撞坏。
由于开奔驰的人比较"有特点",总是向上下左右四个方向开,而且只会在撞到椅子之后改变方向(起步时除外) - -!
现在他给你一张地图,上面标明 他的位置 、 公园里的bench的位置 和 他想到达的位置,可能会有冲出地图的可能
请你告诉他最少撞多少下才能到达目的地,并答应事成之后会给你一辆奔驰..............................................的照片
公园里的bench与奔驰都是无敌的,不会被撞坏。
由于开奔驰的人比较"有特点",总是向上下左右四个方向开,而且只会在撞到椅子之后改变方向(起步时除外) - -!
现在他给你一张地图,上面标明 他的位置 、 公园里的bench的位置 和 他想到达的位置,可能会有冲出地图的可能
请你告诉他最少撞多少下才能到达目的地,并答应事成之后会给你一辆奔驰..............................................的照片
Input
第一行,两个数,分别表示地图的行和列,都不大于50
以下是地图,"."表示地面,"S"表示起点,"E"表示终点,"B"表示bench(什么意思呢?)
保证只有一个终点和一个起点,并不会出现其他字符
以下是地图,"."表示地面,"S"表示起点,"E"表示终点,"B"表示bench(什么意思呢?)
保证只有一个终点和一个起点,并不会出现其他字符
Output
第一行,表示他能不能到达目的地。如果能,就输出"Yes"。否则,输出"No"
如果能到达目的地,就在第二行输出最少的撞击次数
如果能到达目的地,就在第二行输出最少的撞击次数
Sample Input
测试数据1:
5 5
BBBBB
B...B
BSE.B
B...B
BBBBB
测试数据2:
3 3
S..
...
..E
5 5
BBBBB
B...B
BSE.B
B...B
BBBBB
测试数据2:
3 3
S..
...
..E
Sample Output
测试数据1:
Yes
0
测试数据2:
No
Yes
0
测试数据2:
No
Hint
测试数据1:点火后直接向右走
测试数据2:四个方向都会冲出地图
测试数据2:四个方向都会冲出地图
思路:一道深搜题, 搜索的时候要直着走遇到障碍才能转向, 标记的时候可以直接标
记转弯的地方, 避免重复搜索, 因为每次搜索开始时原始方向必定撞墙, 所以来的方
向和原始方向不用再搜, 每次遇到‘B’时展开下次搜索, 因为要找到hit最小是的路径所
以要遍历完才知道谁最小。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>
#define MAX 55
using namespace std;
typedef struct Pos
{
int x;
int y;
int hit; //撞击次数
}pos;
pos sp, ep;
int dir[4][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}}, n, m, minn;
char map[MAX][MAX];
void dfs(pos prepos, int predir) //搜索起点, 原始方向
{
for(int i = 0; i < 4; i++)
{
if((i == predir) || (i == 0 && predir == 1) || (predir == 0 && i == 1) || (predir == 2 && i == 3) || (predir == 3 && i == 2))
{ //此处判断方向是否合适(来的方向不搜(搜过), 原始方向不搜(因为已经堵了),为了节省时间)
continue;
}
pos t;
t.x = prepos.x + dir[i][0];
t.y = prepos.y + dir[i][1];
while(t.x >= 0 && t.x < n && t.y >= 0 && t.y < m && map[t.x][t.y] == '.') //走到头
{
t.x = t.x + dir[i][0];
t.y = t.y + dir[i][1];
}
if(map[t.x][t.y] == 'E') //到达终点, 判断hit是否为最小
{
if(prepos.hit < minn)
{
minn = prepos.hit; //更新最小hit值
}
continue;
}
if(map[t.x][t.y] == 'B') //如果撞墙, 展开下一次深搜
{
t.x -= dir[i][0];
t.y -= dir[i][1];
if(map[t.x][t.y] == 'X') //有可能是已经搜过的点(必须加上,否则死循环)
{
continue;
}
t.hit = prepos.hit + 1;
map[t.x][t.y] = 'X';
dfs(t, i);
map[t.x][t.y] = '.'; //搜完还原标记
}
}
}
int main()
{
int i, j;
cin>>n>>m;
for(i = 0; i < n; i++)
{
for(j = 0; j < m; j++)
{
cin>>map[i][j];
if(map[i][j] == 'S')
{
sp.x = i;
sp.y = j;
sp.hit = 0;
map[i][j] = 'X'; //标记为已搜
}
else if(map[i][j] == 'E')
{
ep.x = i;
ep.y = j;
}
}
}
minn = 0xfffff; //初始化为一个大于50*50的数
dfs(sp, -1); //注意此处的方向, 以为搜的时候不会搜来的方向和原始方向, 所以要初始化成一个无效的方向, 第一次才会搜四个方向
if(minn != 0xfffff) //没变化?说明没搜到
{
cout<<"Yes"<<endl<<minn<<endl;
}
else
{
cout<<"No"<<endl;
}
return 0;
}