宽度有限搜索BFS搜索
B3625 迷宫寻路
题面
题目描述
机器猫被困在一个矩形迷宫里。
迷宫可以视为一个 n×m 矩阵,每个位置要么是空地,要么是墙。机器猫只能从一个空地走到其上、下、左、右的空地。
机器猫初始时位于 (1,1) 的位置,问能否走到 (n,m) 位置。
输入格式
第一行,两个正整数 n,m。
接下来 n 行,输入这个迷宫。每行输入一个长为 m 的字符串,#
表示墙,.
表示空地。
输出格式
仅一行,一个字符串。如果机器猫能走到 (n,m),则输出 Yes
;否则输出 No
。
输入输出样例
输入 #1
3 5 .##.# .#... ...#.
输出 #1
Yes
说明/提示
样例解释
路线如下:(1,1)→(2,1)→(3,1)→(3,2)→(3,3)→(2,3)→(2,4)→(2,5)→(3,5)(1,1)→(2,1)→(3,1)→(3,2)→(3,3)→(2,3)→(2,4)→(2,5)→(3,5)
题解
BFS的思路是从标点(1,1)开始逐层往外扩展,此时我们选择建立一个队列用来保存待访问的点,只要队列非空,判断越界情况和其他非法情况后一直访问相邻位置,可以用一个结构组表示x,y坐标。为了避免重复访问的情况,我们使用vis函数。访问一个点后把vis[x][y]负值与1。到最后如果队列的某个点到了(n,m) 终点,答案设为true,输出这个情况YES。
代码
#include <bits/stdc++.h>
using namespace std;
int n, m, isOk;
char a[105][105];
bool vis[105][105];
struct Pos {
int x, y;
Pos(int ax, int ay) {
x = ax, y = ay;
}
};
void bfs() {
queue<Pos> q;
q.push(Pos(1, 1));
while(!q.empty()) {
Pos now = q.front();
q.pop();
int x = now.x, y = now.y;
if(x < 1 || x > n) continue;
if(y < 1 || y > m) continue;
if(a[x][y] == '#') continue;
if(vis[x][y]) continue;
vis[x][y] = 1;
if(x == n && y == m) isOk = true;
q.push(Pos(x + 1, y));
q.push(Pos(x - 1, y));
q.push(Pos(x, y + 1));
q.push(Pos(x, y - 1));
}
}
int main() {
cin >> n >> m;
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++)
cin >> a[i][j];
bfs();
if(isOk)
cout << "Yes" << endl;
else
cout << "No" << endl;
return 0;
}
P1451 求细胞数量
题面
题目描述
一矩形阵列由数字 0 到 9 组成,数字 1 到 9 代表细胞,细胞的定义为沿细胞数字上下左右若还是细胞数字则为同一细胞,求给定矩形阵列的细胞个数。
输入格式
第一行两个整数代表矩阵大小 n 和 m。
接下来 n 行,每行一个长度为 m 的只含字符 0
到 9
的字符串,代表这个 n×m 的矩阵。
输出格式
一行一个整数代表细胞个数。
输入输出样例
输入 #1
4 10 0234500067 1034560500 2045600671 0000000089
输出 #1
4
题解
这道题的意思,只要相邻的数不是0,那么它和其他相邻的数构成一个细胞,例如样例中的12是一个细胞,23453456456是一个细胞,67,567189,一共四个细胞。这一道题可以用BFS也能用DFS搜索方法。在队列非空的状态依次判断非法情况,避免重复访问,判断是否到终点并寻找答案,继续访问相邻位置。在main循环中bfs之前要判断这个数是否是细胞,是否访问过。Vis可以当访问数组的同时在这类题当成染色“Flood Fill”
注意事项:
- 若(x,y)是细胞且无色,则答案+1、并将其所属整个细胞染色
- BFS 的实现 :当队列非空,访问队首,并将相邻结点人队
代码
#include <bits/stdc++.h>
using namespace std;
int n, m, ans;
char a[105][105];
bool vis[105][105];
struct Pos {
int x, y;
Pos(int ax = 0, int ay = 0) {
x = ax; // 该结点的 x 值初始化为 ax
y = ay; // 该结点的 y 值初始化为 ay
}
};
// 从 (x, y) 开始 BFS 整个细胞
void bfs(int x, int y) {
queue<Pos> q;
q.push(Pos(x, y)); // 将 (x,y) 入队
while(!q.empty()) { // 当队列非空
Pos now = q.front(); // 现在处理队首结点
q.pop(); // 队首出队
int x = now.x, y = now.y;
if(x < 1 || x > n) continue;
if(y < 1 || y > m) continue;
if(a[x][y] == '0') continue; // 不是细胞点
if(vis[x][y]) continue; // 如果这个点被访问过则跳过
vis[x][y] = 1; // 用 vis 数组避免重复访问
q.push(Pos(x+1, y)); // 将上方结点加入到队列
q.push(Pos(x-1, y)); // 将下方结点加入到队列
q.push(Pos(x, y+1)); // 将左方结点加入到队列
q.push(Pos(x, y-1)); // 将右方结点加入到队列
}
}
int main() {
cin >> n >> m;
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++)
cin >> a[i][j];
for(int x = 1; x <= n; x++)
for(int y = 1; y <= m; y++)
if(a[x][y]!='0'&& vis[x][y]==0) { // (x,y) 这个点是细胞点,且未访问过
ans++;
bfs(x,y); // 开始对 (x,y) 这个点进行 BFS
}
cout << ans << endl;
return 0;
}
B3626 跳跃机器人
题面
题目描述
地上有一排格子,共 n 个位置。机器猫站在第一个格子上,需要取第 n 个格子里的东西。
机器猫当然不愿意自己跑过去,所以机器猫从口袋里掏出了一个机器人!这个机器人的行动遵循下面的规则:
- 初始时,机器人位于 1 号格子
- 若机器人目前在 x 格子,那么它可以跳跃到 x−1,x+1,2x 里的一个格子(不允许跳出界)
问机器人最少需要多少次跳跃,才能到达 n 号格子。
输入格式
仅一行,一个正整数,表示 n。
输出格式
仅一行,一个正整数,表示最少跳跃次数。
输入输出样例
输入 #1
30
输出 #1
6
输入 #2
50
输出 #2
7
输入 #3
64
输出 #3
6
输入 #4
63
输出 #4
8
说明/提示
样例解释
第一组样例:
1→2→4→8→16→15→301→2→4→8→16→15→30
第二组样例:
1→2→3→6→12→24→25→501→2→3→6→12→24→25→50
第三组样例:
1→2→4→8→16→32→641→2→4→8→16→32→64
第四组样例:
1→2→4→8→16→32→31→62→631→2→4→8→16→32→31→62→63
请注意在本组样例中,63 不能通过 64−1 得到,因为格子总数为 63,没有第 64 个格子。
题解
代码
#include <bits/stdc++.h>
using namespace std;
struct Pos {
int x, cost;
Pos(int ax = 0, int acost = 0) {
x = ax, cost = acost;
}
};
int n;
bool vis[1000005];
void bfs() {
int x=1, cost=0;
queue <Pos> q;
q.push(Pos(x,cost));
while(!q.empty()) {
Pos now = q.front();
q.pop();
int x = now.x, cost = now.cost;
if(x<1||x>n) // 处理越界,如果 x 不在 [1,n] 范围内
continue;
if(vis[x]) // 用 vis 数组判断重复
continue;
vis[x] = 1; // 用 vis 数组标记这个数字被访问过
if(x == n) {
cout << cost << endl;
return;
}
q.push(Pos(x-1, cost+1));
q.push(Pos(x+1,cost+1));
q.push(Pos(2*x, cost+1));
}
}
int main() {
cin >> n;
bfs();
return 0;
}