BFS - 会拐弯的眼睛 - 中国计量大学现代科技学院第四届“中竞杯”程序设计校赛
题意:
给 定 一 个 n × m 的 矩 阵 , 计 算 从 起 点 到 终 点 , 最 少 需 要 ′ ′ 拐 弯 ′ ′ 几 次 。 给定一个n×m的矩阵,计算从起点到终点,最少需要''拐弯''几次。 给定一个n×m的矩阵,计算从起点到终点,最少需要′′拐弯′′几次。
输入描述:
输 入 第 一 行 六 个 正 整 数 n , m 描 述 地 图 大 小 , s t a r t x , s t a r t y , e n d x , e n d y 描 述 起 点 , 终 点 。 保 证 : 1 ≤ n , m ≤ 5000 , 0 ≤ s t a r t x , e n d x ≤ n − 1 , 0 ≤ s t a r t y , e n d y ≤ m − 11 ≤ n , m ≤ 5000 , 0 ≤ s t a r t x , e n d x ≤ n − 1 , 0 ≤ s t a r t y , e n d y ≤ m − 1 接 下 来 n 行 , 每 行 一 个 长 度 为 m 的 01 串 , 0 代 表 可 以 走 的 空 地 , 1 代 表 不 能 走 的 墙 壁 输入第一行六个正整数 n,m 描述地图大小,startx, starty, endx, endy 描述起点,终点。 \\\ \\保证:\\ 1 \leq n,m \leq 5000,0 \leq startx,endx \leq n-1, \\0 \leq starty,endy \leq m-11≤n,m≤5000,\\0≤startx,endx≤n−1,0≤starty,endy≤m−1\\接下来 n 行,每行一个长度为 m 的 01 串,0 代表可以走的空地,1 代表不能走的墙壁 输入第一行六个正整数n,m描述地图大小,startx,starty,endx,endy描述起点,终点。 保证:1≤n,m≤5000,0≤startx,endx≤n−1,0≤starty,endy≤m−11≤n,m≤5000,0≤startx,endx≤n−1,0≤starty,endy≤m−1接下来n行,每行一个长度为m的01串,0代表可以走的空地,1代表不能走的墙壁
输出描述:
输 出 一 行 一 个 正 整 数 表 示 答 案 。 输出一行一个正整数表示答案。 输出一行一个正整数表示答案。
若 无 法 到 达 终 点 , 则 输 出 − 1. 若无法到达终点,则输出-1. 若无法到达终点,则输出−1.
示例1
输入
3 3 0 0 2 2
000
110
110
输出
1
示例2
输入
3 3 0 0 2 2
001
101
100
输出
2
分析:
本 题 很 容 易 想 到 用 B F S 来 求 解 , 关 键 在 于 , 如 何 考 虑 ′ ′ 拐 弯 ′ ′ 。 本题很容易想到用BFS来求解,关键在于,如何考虑''拐弯''。 本题很容易想到用BFS来求解,关键在于,如何考虑′′拐弯′′。
参 照 B F S 的 算 法 思 想 , 我 们 可 以 把 无 需 拐 弯 可 直 通 的 点 看 作 是 同 一 层 结 点 。 参照BFS的算法思想,我们可以把无需拐弯可直通的点看作是同一层结点。 参照BFS的算法思想,我们可以把无需拐弯可直通的点看作是同一层结点。
对 于 每 一 个 结 点 , 我 们 从 上 下 左 右 四 个 方 向 不 断 扩 展 , 直 至 不 能 扩 展 为 止 。 对于每一个结点,我们从上下左右四个方向不断扩展,直至不能扩展为止。 对于每一个结点,我们从上下左右四个方向不断扩展,直至不能扩展为止。
贪 心 地 去 想 , 因 为 朝 同 一 个 方 向 扩 展 的 花 费 为 0 , 那 么 对 同 一 方 向 , 我 们 应 当 尽 量 多 地 扩 展 新 的 结 点 。 贪心地去想,因为朝同一个方向扩展的花费为0,那么对同一方向,我们应当尽量多地扩展新的结点。 贪心地去想,因为朝同一个方向扩展的花费为0,那么对同一方向,我们应当尽量多地扩展新的结点。
这 样 就 能 够 保 证 , 每 个 点 第 一 次 被 扩 展 到 时 就 是 最 近 距 离 ( 最 少 花 费 ) 。 这样就能够保证,每个点第一次被扩展到时就是最近距离(最少花费)。 这样就能够保证,每个点第一次被扩展到时就是最近距离(最少花费)。
仔细去思考这个做法:
实 际 上 我 们 是 把 每 个 结 点 上 下 左 右 能 够 直 达 的 所 有 未 曾 遍 历 过 的 结 点 看 作 是 同 一 层 结 点 了 。 实际上我们是把每个结点上下左右能够直达的所有未曾遍历过的结点看作是同一层结点了。 实际上我们是把每个结点上下左右能够直达的所有未曾遍历过的结点看作是同一层结点了。
每 次 操 作 我 们 把 同 一 层 的 结 点 全 都 入 队 , 继 续 再 做 同 样 地 操 作 。 每次操作我们把同一层的结点全都入队,继续再做同样地操作。 每次操作我们把同一层的结点全都入队,继续再做同样地操作。
代码:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<unordered_map>
#include<vector>
#define P pair<int,int>
#define x first
#define y second
#define ll long long
using namespace std;
const int N = 5010, inf = 0x3f3f3f3f;
struct node
{
int x, y, dir, step;
};
char str[N][N];
int n, m;
node S, E;
int dir[4][2]={{1,0}, {-1,0}, {0,1}, {0,-1}};
int dis[N][N];
bool check(int x,int y)
{
if(x<0 || x>=n || y<0 ||y>=m || str[x][y]=='1') return false;
return true;
}
int bfs()
{
memset(dis,0x3f,sizeof dis);
queue<node> Q;
for(int i=0;i<4;i++) Q.push({S.x,S.y,-1,-1});
dis[S.x][S.y]=-1;
while(Q.size())
{
node u = Q.front();
Q.pop();
for(int i=0;i<4;i++)
{
if(i==u.dir) continue;
for(int j=1;;j++)
{
int x = u.x + dir[i][0]*j, y = u.y + dir[i][1]*j;
if(!check(x,y)) break;
if(dis[x][y]!=inf) continue;
dis[x][y]=u.step+1;
if(x==E.x && y==E.y) return dis[x][y];
Q.push({x,y,i,dis[x][y]});
}
}
}
return -1;
}
int main()
{
scanf("%d%d%d%d%d%d",&n,&m,&S.x,&S.y,&E.x,&E.y);
for(int i=0;i<n;i++) scanf("%s",str[i]);
printf("%d\n",bfs());
return 0;
}