ATCODER ABC 450 C题解

ATCODER ABC 450 C

Atcoder ABC 450 C\]([C - Puddles](https://atcoder.jp/contests/abc450/tasks/abc450_c)) ## 题意概述: 二维字符数组中,找到联通的.的组合并且处在内部,没有点在最外层 ## 难点: 因为想不到或者不知道这道题的算法是什么,我想枚举模拟,但是在枚举模拟的过程中,我发现,我模拟从一个串的开始到串的末尾,这个过程很难模拟出来,所以暴力做法也写不出来,最后,看官方题解以及问ai,才知道这道题要用BFS(广度优先搜索) ## BFS: ### 为什么要用BFS 1. 这道题是一个连通块问题,等效于要求我们统计"不漏水"的水坑,`bfs`的核心思想就是从一个点开始,向四周扩散,所以这道题的要求很契合bfs ### 具体思路 * 用两个数组表示平移到上下左右 * 用一个二维bool数组表示该格子是否被扫描过 * 循环每个字符 * 假如一个字符没被扫描过,并且是`.`,以它为头建造一个队列(存储pair),记住存入队列就马上标记(原因见下文). * 设定一个bool数来表示连通串是否有点在边界 * bfs寻找:首先判断当前的坐标是否在边界内,即使在边界,还是要把邻居找完,不然之后还是循环到邻居还是要再找,可能导致重复找邻居,效率低下.找邻居(注意判断坐标边界条件,将邻居push进队列,进队列就标记) * 进队列就标记的原因: 如下例子所示: ### 1. 2×2 地图的"包抄"过程 假设四个点全是水坑 `.`: * **A** \\((0,0)\\) ------ 起点 * **B** \\((1,0)\\) ------ A 的下方邻居 * **C** \\((0,1)\\) ------ A 的右方邻居 * **D** \\((1,1)\\) ------ **B 的右方邻居,同时也是 C 的下方邻居** 1. **第一步:处理 A \\((0,0)\\)** * A 看向四周,发现了 B \\((1,0)\\) 和 C \\((0,1)\\)。 * A 把 B 和 C 都丢进队列排队。 * *此时队列* :`[B, C]`。**注意:此时 B 和 C 还没出队,所以还没被贴上 `cg=1` 的标签。** 2. **第二步:轮到 B \\((1,0)\\) 出队** * B 贴上标签 `cg[1][0]=1`。 * B 看向它的邻居,发现了 **D \\((1,1)\\)**。 * B 发现 D 还没贴标签,于是把 **D 丢进队列**。 * *此时队列* :`[C, D]`。**注意:此时 D 已经在排队了,但因为还没出队,它的标签 `cg[1][1]` 依然是 0。** 3. **第三步:轮到 C \\((0,1)\\) 出队** * C 贴上标签 `cg[0][1]=1`。 * C 看向它的邻居,也发现了 **D \\((1,1)\\)**! * **关键冲突点** :C 检查 `cg[1][1]`,发现竟然是 **0**(因为 D 还在后面排队呢,没轮到它贴标签)。 * C 以为 D 是个没人管的"新发现",于是**又把 D 丢进了一次队列**。 * *最终队列* :`[D, D]`。 *** ** * ** *** ### 2. 为什么这很可怕? 虽然 \\((1,0)\\) 和 \\((0,1)\\) 互不相识,但它们像两个不沟通的部门,同时看中了同一个员工 **D**。 * 在一个大迷宫里,任何一个空格子(比如 \\((x, y)\\))通常都有 4 个邻居。 * 这意味着,如果你不在**入队那一刻** 就贴上标签,这个格子可能会被它的上下左右邻居**每人举报一次**。 * 在你的 `while` 循环里,原本这个格子只需要处理 1 次,现在却要处理 4 次。而这 4 次处理又会引发出更多的重复......这种冗余会像病毒一样在你的队列里疯狂繁殖。 * 假如队列空后bool数不变,那么++count ## 代码: ```cpp #include using i64 = long long; int dx[] = {1, -1, 0, 0}; int dy[] = {0, 0, 1, -1}; void solve(){ int h, w; std::cin >> h >> w; std::vector s(h); for(int i = 0; i < h; ++i){ std::cin >> s[i]; } std::vector> cg(h,std::vector (w,0)); int count = 0; for(int i = 0; i < h; ++i){ for(int j = 0; j < w; ++j){ if(s[i][j] == '.' && cg[i][j] == 0){ std::queue> q; q.push({i,j}); cg[i][j] = 1; bool is = 1; while(!q.empty()){ auto[x,y] = q.front(); q.pop(); int nx, ny; if(x == 0 || x == h - 1 || y == 0 || y == w - 1){ is = 0; } for(int k = 0 ; k < 4; ++k){ nx = x + dx[k]; ny = y + dy[k]; if(nx >= 0 && nx < h && ny >= 0 && ny < w){ if(s[nx][ny] == '.' && cg[nx][ny] == 0){ q.push({nx,ny}); cg[nx][ny] = 1; } } } } if(is == 1){ ++count; } } } } std::cout << count; } int main(){ std::ios::sync_with_stdio(false); std::cin.tie(nullptr); solve(); return 0; } ```

相关推荐
王老师青少年编程21 小时前
csp信奥赛C++高频考点专项训练之贪心算法 --【线性扫描贪心】:数列分段 Section I
c++·算法·编程·贪心·csp·信奥赛·线性扫描贪心
王老师青少年编程21 小时前
csp信奥赛C++高频考点专项训练之贪心算法 --【线性扫描贪心】:分糖果
c++·算法·贪心算法·csp·信奥赛·线性扫描贪心·分糖果
_日拱一卒21 小时前
LeetCode:2两数相加
算法·leetcode·职场和发展
py有趣21 小时前
力扣热门100题之零钱兑换
算法·leetcode
董董灿是个攻城狮21 小时前
Opus 4.7 来了,我并不建议你升级
算法
leaves falling1 天前
C++模板进阶
开发语言·c++
无敌昊哥战神1 天前
【保姆级题解】力扣17. 电话号码的字母组合 (回溯算法经典入门) | Python/C/C++多语言详解
c语言·c++·python·算法·leetcode
脱氧核糖核酸__1 天前
LeetCode热题100——238.除了自身以外数组的乘积(题目+题解+答案)
数据结构·c++·算法·leetcode
再卷也是菜1 天前
算法提高篇(1)线段树(上)
数据结构·算法
py有趣1 天前
力扣热门100题之单词拆分
算法·leetcode