红与黑(bfs, acwing)

题目描述:

有一间长方形的房子,地上铺了红色、黑色两种颜色的正方形瓷砖。
你站在其中一块黑色的瓷砖上,只能向相邻(上下左右四个方向)的黑色瓷砖移动。
请写一个程序,计算你总共能够到达多少块黑色的瓷砖。

输入格式:

输入包括多个数据集合。
每个数据集合的第一行是两个整数 W 和 H,分别表示 x 方向和 y 方向瓷砖的数量。
在接下来的 H 行中,每行包括 W 个字符。每个字符表示一块瓷砖的颜色,规则如下
1)'.':黑色的瓷砖;

2)'#':红色的瓷砖;
3)'@':黑色的瓷砖,并且你站在这块瓷砖上。该字符在每个数据集合中唯一出现一次。

当在一行中读入的是两个零时,表示输入结束。

输出格式:

对每个数据集合,分别输出一行,显示你从初始位置出发能到达的瓷砖数(记数时包括初始位置的瓷砖)。

数据范围:

1≤W,H≤20

输入样例:

复制代码
6 9 
....#. 
.....# 
...... 
...... 
...... 
...... 
...... 
#@...# 
.#..#. 
0 0

输出样例:

复制代码
45

分析步骤:

第一:我们拿到这道题应该一眼就能够这是一道要搜索的题目,我们有红色瓷砖的话就不可以行走了,相当于一座高山;我们的黑色瓷砖可以行走,我们搜索也只能搜索黑色瓷砖,相当于一旦当海水进入之后只能向低洼的地区流。 想到此处我们应该运用Flood Fill 和 BFS 就能够解出答案。

第二:书写主函数构建整体架构

由于这题没有固定的输入次数,所以应该在while循环的判断中输入值,并且判断是否为0即可,每次输入一个新的值我们就应该清除一下我们的地图,定义一个cnt为计数器。随后将地图输入进去,并且判断一下哪个坐标为"@"并将其横纵坐标记录下来。之后进行bfs搜索

cpp 复制代码
int main()
{
    while(cin>>n>>m,m||n){
    memset(map, 0, sizeof map);
    cnt = 1 ;
    for(int i = 0 ; i < m ;  i++){
        for(int j = 0 ; j < n ; j ++){
            cin>>map[i][j];
            if(map[i][j] == '@') {
                x1 = i , y1 = j; 
            }
        }
    }
    
    cout<<bfs(x1,y1)<<endl;
    }
    return 0;
}

第三:书写BFS

每次进入我们的 bfs 都应该更新一下我们的坐标状态,因为我们不止有一组地图 。一般我们书写bfs都会手写队列。所以将此点改变状态改为true标记为走过了,定义头节点为0 ,尾节点为0,用他们来判断我们的队列是否为空 , 将刚刚进入的点放入队列。

进入while循环只要队列不为空就一直循环下去,因为队列里有符合条件的点还没有判断。定义一个迭代器去向后遍历队列,随后进行四方搜索,所搜看看这个点周围是否存在其他的黑色瓷砖。之后要判断我们新的坐标的这个点是否符合条件。如果1.边界符合条件;2.没有重复走过;3.不是红色瓷砖,都满足的话那么这个点就是我们要找的点,将其放入队列,更新状态,计数器++。最后返回cnt的答案。

cpp 复制代码
int bfs(int xx , int yy){
    memset(st, false, sizeof st);
    st[xx][yy] = true;
    int hh = 0 , tt = 0 ;
    q[0] = {xx, yy};
    while(hh <= tt){
        auto t = q[hh++];
        for(int i = 0 ; i < 4 ; i ++){
           int a = t.x+dx[i] , b = t.y+dy[i];
           if(a < 0 || b < 0 || a >= m || b >= n) continue;
           if(st[a][b]) continue;
           if(map[a][b] == '#') continue;
           st[a][b] = true;
           q[++tt] = {a,b};
           cnt++;
        }
    }
   return cnt; 
}

注意注意:我们bfs的书写是相当有规律的,

首先更新该点状态并将其放入队列,定义头节点尾节点。

进入while循环只要不空就一直循环下去,利用迭代器自己向后遍历,

进行方向搜索判断问题一般是三个问题:1.是否已经走过了这个点;2.是否有边界问题;3.是否有障碍物而无法通过

如果都没有问题则将其入队,更新坐标点的状态

最后返回

大家记住即可。很简单,到时候遇到了BFS的题目就直接套上去就行。

代码:

cpp 复制代码
#include <iostream>
#include <cstring>
#include <algorithm>
#define x first
#define y second

using namespace std;

const int N = 30;
int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1};
int n , m ;
int x1=-1 , y1=-1;
int cnt = 1 ;
char map[N][N];
typedef pair<int, int> PII;
PII q[N*N];
bool st[N][N];

int bfs(int xx , int yy){
    memset(st, false, sizeof st);
    st[xx][yy] = true;
    int hh = 0 , tt = 0 ;
    q[0] = {xx, yy};
    while(hh <= tt){
        auto t = q[hh++];
        for(int i = 0 ; i < 4 ; i ++){
           int a = t.x+dx[i] , b = t.y+dy[i];
           if(a < 0 || b < 0 || a >= m || b >= n) continue;
           if(st[a][b]) continue;
           if(map[a][b] == '#') continue;
           st[a][b] = true;
           q[++tt] = {a,b};
           cnt++;
        }
    }
   return cnt; 
}

int main()
{
    while(cin>>n>>m,m||n){
    memset(map, 0, sizeof map);
    cnt = 1 ;
    for(int i = 0 ; i < m ;  i++){
        for(int j = 0 ; j < n ; j ++){
            cin>>map[i][j];
            if(map[i][j] == '@') {
                x1 = i , y1 = j; 
            }
        }
    }
    
    cout<<bfs(x1,y1)<<endl;
    }
    return 0;
}
相关推荐
艾莉丝努力练剑1 小时前
【Linux基础开发工具 (三)】Vim从入门到精通(下):效率翻倍的编辑技巧与个性化配置攻略
linux·运维·服务器·c++·ubuntu·centos·vim
yuuki2332331 小时前
【数据结构】栈
c语言·数据结构·后端
草莓熊Lotso1 小时前
C++ STL set 系列完全指南:从底层原理、核心接口到实战场景
开发语言·c++·人工智能·经验分享·网络协议·算法·dubbo
做怪小疯子3 小时前
LeetCode 热题 100——子串——和为 K 的子数组
算法·leetcode·职场和发展
zl_vslam4 小时前
SLAM中的非线性优-3D图优化之李群李代数在Opencv-PNP中的应用(四)
人工智能·opencv·算法·计算机视觉
AA陈超6 小时前
ASC学习笔记0014:手动添加一个新的属性集
c++·笔记·学习·ue5
Run_Teenage6 小时前
C++:智能指针的使用及其原理
开发语言·c++·算法
mit6.8248 小时前
二维差分+前缀和
算法
民乐团扒谱机8 小时前
自然的算法:从生物进化到智能优化 —— 遗传算法的诗意与硬核“
算法
希望有朝一日能如愿以偿8 小时前
力扣每日一题:仅含1的子串数
算法·leetcode·职场和发展