ATCODER ABC 450 C题解

ATCODER ABC 450 C

Atcoder ABC 450 C(C - Puddles)

题意概述:

二维字符数组中,找到联通的.的组合并且处在内部,没有点在最外层

难点:

因为想不到或者不知道这道题的算法是什么,我想枚举模拟,但是在枚举模拟的过程中,我发现,我模拟从一个串的开始到串的末尾,这个过程很难模拟出来,所以暴力做法也写不出来,最后,看官方题解以及问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 <bits/stdc++.h>

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<std::string> s(h);
for(int i = 0; i < h; ++i){
	std::cin >> s[i];
}
std::vector<std::vector<bool>> cg(h,std::vector<bool> (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<std::pair<int, int>> 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;
}
相关推荐
FlightYe7 小时前
视界原理之3D视频(四):裸眼、眼镜和头显
android·linux·c++·3d·ffmpeg·音视频
ZhengEnCi7 小时前
GPT-6 Astra 爆改 Qwen 权重真有那么神吗:权重空间编程 0.016% 参数的真相
算法·架构
罗西的思考7 小时前
【轻量化复刻大模型 / KIMI K3】KDA(Kimi Delta Attention):并行
人工智能·算法·机器学习
by209998 小时前
C++ 智能指针的所有权与使用
开发语言·c++·经验分享
Rover Ramble8 小时前
C++ 用互斥锁实现读写锁
开发语言·c++
你怎么知道我是队长9 小时前
C++零基础入门第2周:数据类型、运算符与表达式完全指南(附20段可运行代码+避坑清单)
c++
say_fall9 小时前
【Linux系统编程】Ext 文件系统:磁盘与存储、文件与目录、现代计算机究竟如何寻找文件
linux·运维·服务器·数据库·c++
雪落漂泊9 小时前
C++算法 滑动窗口篇(下)
开发语言·c++
夜不会漫长9 小时前
C++:红黑树
数据结构·算法
AI备案指南-满满10 小时前
算法备案审核不通过,一般是什么原因?
java·人工智能·算法·大模型备案·算法备案·大模型登记