宽度有限搜索BFS搜索数及B3625 迷宫寻路 P1451 求细胞数量 B3626 跳跃机器人

宽度有限搜索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;
} 

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值