URL:小白教育赛3
题目描述
劳 e e e和桶子在打派的时候被一个艾许的电弧陷阱控在原地动弹不得,于是他们想办法找出哪些地方是可以去的,哪些地方是不能去的。
给定一个由字符构成的 N ∗ M N * M N∗M的矩阵,其中包括:
.
表示这是一块空地;#
表示这是一个电弧陷阱;
电弧陷阱会使得它的上下左右四个方向充满电弧,走到这些地方就会被困住,不能再行动。
他们想知道如果从一个地方出发,最多可以到达多少个地方?
注意:数据保证至少有一个空地。
输入格式
第一行输入 N N N和 M M M。
接下来 N N N行,每行输入 M M M个字符。
1 ≤ N , M ≤ 1000 1 \le N, M \le 1000 1≤N,M≤1000。
输出格式
输出一个整数表示答案。
输入样例1
3 5
.#...
.....
.#..#
输出样例1
9
输入样例2
5 3
#.#
...
#.#
...
...
输出样例2
7
思路
类似这种给一个矩阵,然后有些位置不能去、被挡住、有传送门之类的,一般都需要用到 b f s bfs bfs。这种题就类似于走迷宫,需要保证走过的点不要再走,否则会让时间复杂度变高。
显然电弧陷阱会将整个矩阵分成好几部分连通区域,我们只需要在遍历矩阵的时候判断一下当前位置,是否可以作为出发点即可开始 b f s bfs bfs。
此时一个连通部分的答案 = .
的数量 + 电弧
数量。
.
的数量我们可以通过找到所有不会被电弧困住的地方
来计算,而难点在于如何算出 电弧
的数量。
最简单的方法就是使用set
维护一个pair<x, y>
直接去重,最后加上 set.size()
即可。
容易出错的地方在于,如果选择将 # 周围的点修改为其他字符做标记,那么一定要在
输入完成后
和进行bfs之前
进行标记。还需要注意,题目保证了至少一个点为 . ,因此答案至少为 1。
代码
#include "bits/stdc++.h"
char mp[1007][1007];
int vis[1007][1007], n, m, ans;
const int dir[] = {0, 1, 0, -1, 0};
bool check_boom(int x, int y) { // 检查 {x, y} 是否有电弧
for (int i = 0; i < 4; ++ i) {
int nx = x + dir[i], ny = y + dir[i + 1];
if (mp[nx][ny] == '#') return false;
}
return true;
}
bool check(int x, int y) {
return x >= 1 and x <= n and y >= 1 and y <= m and mp[x][y] != '#' and check_boom(x, y) and vis[x][y] == 0;
}
void bfs(int x, int y) {
// . and 电弧
std::set<std::pair<int, int>> set_a;
std::set<std::pair<int, int>> set_b;
// now {x, y}
std::queue <std::pair<int, int>> q;
q.push({x, y});
while (!q.empty()) {
auto top = q.front(); q.pop();
set_a.insert(top);
for (int i = 0; i < 4; ++ i) {
int nx = top.first + dir[i], ny = top.second + dir[i + 1]; // next_x, next_y
if (check(nx, ny)) {
q.push({nx, ny});
vis[nx][ny] = 1;
}
}
}
// 遍历 . 的 set,检查其周围是否有 电弧
for (auto &p : set_a) {
for (int i = 0; i < 4; ++ i) {
int nx = p.first + dir[i], ny = p.second + dir[i + 1];
if (mp[nx][ny] == '.' and vis[nx][ny] == 0)
set_b.insert({nx, ny});
}
}
int num = set_a.size() + set_b.size();
ans = std::max(ans, num);
}
signed main() {
std::cin >> n >> m;
for (int i = 1; i <= n; ++ i) {
for (int j = 1; j <= m; ++ j) {
std::cin >> mp[i][j];
}
}
for (int i = 1; i <= n; ++ i) {
for (int j = 1; j <= m; ++ j) {
if (vis[i][j] == 0 and mp[i][j] == '.') {
ans = std::max(1, ans); // 只要有一个位置为 . ,答案就至少为1
if (check_boom(i, j)) bfs(i, j);
}
}
}
std::cout << ans;
}