题目描述
给定一个 n 行 m 列的地牢,其中 '.' 表示可以通行的位置,'X' 表示不可通行的障碍,牛牛从 (x0 , y0 ) 位置出发,遍历这个地牢,和一般的游戏所不同的是,他每一步只能按照一些指定的步长遍历地牢,要求每一步都不可以超过地牢的边界,也不能到达障碍上。地牢的出口可能在任意某个可以通行的位置上。牛牛想知道最坏情况下,他需要多少步才可以离开这个地牢。
输入描述:
每个输入包含 1 个测试用例。每个测试用例的第一行包含两个整数 n 和 m(1 <= n, m <= 50),表示地牢的长和宽。接下来的 n 行,每行 m 个字符,描述地牢,地牢将至少包含两个 '.'。接下来的一行,包含两个整数 x0, y0,表示牛牛的出发位置(0 <= x0 < n, 0 <= y0 < m,左上角的坐标为 (0, 0),出发位置一定是 '.')。之后的一行包含一个整数 k(0 < k <= 50)表示牛牛合法的步长数,接下来的 k 行,每行两个整数 dx, dy 表示每次可选择移动的行和列步长(-50 <= dx, dy <= 50)
输出描述:
输出一行一个数字表示最坏情况下需要多少次移动可以离开地牢,如果永远无法离开,输出 -1。以下测试用例中,牛牛可以上下左右移动,在所有可通行的位置.上,地牢出口如果被设置在右下角,牛牛想离开需要移动的次数最多,为3次。
示例1
输入
复制
3 3 ... ... ... 0 1 4 1 0 0 1 -1 0 0 -1
输出
复制
3
思路:要用一个队列来遍历 保存 某个点的周围的点;
出队 将新的点入队;改变step[i][j]的值;
d[k][2]在这里用点的方式存储;
vector<Position>pos;
//构建一个数组;
for
(
int
i=0;i<K;i++)
{
int
x,y;
cin>>x>>y;
pos.emplace_back(x,y);
}
代码:
#include<iostream>
#include <vector>//容器;
#include <assert.h>//断言
#include<ctime>//时间
#include<cmath>//数学
#include <string>//字符串
#include <algorithm>//算法头文件;
#include<map>
#include<set>
#include<limits.h>
#include<queue>
using namespace std;
using ll=long long;
int n,m;
vector<vector<char>>gra;
struct Point
{
int x,y;
Point(int X,int Y):x(X),y(Y){};
bool isOk(){return x>=0&&x<n&&y>=0&&y<m&&gra[x][y]=='.';}
Point add(Point &p){return Point(x+p.x,y+p.y);}
};
int main()
{
cin>>n>>m;
for(int i=0;i<n;i++)
{
vector<char>temp(m);
for(int j=0;j<m;j++)
cin>>temp[j];
gra.push_back(temp);
}
int x0,y0;
cin>>x0>>y0;
Point P0(x0,y0);
int K;
cin>>K;
vector<Point>pos;//构建一个数组表示他的邻接点;
for(int i=0;i<K;i++)
{
int dx,dy;
cin>>dx>>dy;
pos.emplace_back(dx,dy);
}
vector<vector<int>>step(50,vector<int>(50,100));//表示的是一个 走的步数的数组;
step[x0][y0]=0;//注意起始点的值 应该为0;
queue<Point>queue;
queue.push(P0);
while(queue.size())
{
auto cur=queue.front();
queue.pop();
for(int i=0;i<K;i++)
{
auto next=cur.add(pos[i]);
if(next.isOk()&&step[cur.x][cur.y]+1<step[next.x][next.y])
{
step[next.x][next.y]=step[cur.x][cur.y]+1;
queue.push(next);
}
}
}
int res=0;
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
if(gra[i][j]=='.')
res=max(res,step[i][j]);
}
}
if(res==100)
cout<<-1<<endl;
else
cout<<res<<endl;
return 0;
}
注意 bfs 与dfs的比较
1、二维数组的题目 当N小于20的适用于dfs 当N《=200 N<=1000的 一定不能用dfs;不仅仅是整个题目不能用dfs 其中的每一步 都不能用dfs;
BFS的基本步骤
- 将初始点(一个或多个)加入到集合尾;
- 从集合(队列)头去取出点,判断初始点的周边店,将符合条件的点加入到队列中
- 重复二操作 直到集合为空;(一般每一个点智能加入队列一次);
一般来说能用dfs解决的问题都能用bfs来解决;
dfs(深度搜索的同时 考虑回溯)
BFS=队列、入队、出队;搜索到的一定是最优解
DFS=栈、压栈、出栈;搜索到的不一定是最优解; 一般情况下需要剪枝操作