Loading

Daiwa Securities Co. Ltd. Programming Contest 2024(AtCoder Beginner Contest 383)-C题解

题目大意

一个 \(H\) 行和 \(W\) 列的网格图。\((i, j)\) 表示从上到下第 \(i\) 行和从左到下第 \(j\) 列的单元格。

每个单元格用字符 \(S_{i,j}\) 表示。如果 \(S_{i,j}\)#,则该单元格有一个障碍物;如果 \(S_{i,j}\). 则该单元格是空的;如果 \(S_{i,j}\)H,则该单元网格图上安装了加湿器。

如果在不穿过障碍的情况下,可以从至少一个放了加湿器的单元格通过最多 \(D\) 次向上、向下、向左或向右移动到达某个单元个,则认为该单元格已加湿。注意:任何有加湿器的单元格都是加湿的。

请你输出已加湿的单元格的个数。

思路

看题目不难发现这道题就是个网格图BFS,但是直接从每个加湿器单元格去做一变网格图BFS的话就会发现你 TLE 了,因为这么干复杂度是 \(O(n^2)\) 的,既然直接 BFS 不可行那么我们还有什么办法呢,答案是多源BFS。

多源BFS是什么:多源BFS,即同时存在多个起点,然后要求计算出图中任意一个点距离所有起点的最短距离,即图中任意点到每个起点的距离的最小值。

好了,知道了思路那么答案是啥呢?我们设一个单元格距离任意一个起点(加湿器单元格)的距离为 \(dist_{i,j}\),那么答案就是 \(dist_{i,j}\) \(\le D\) 的个数。

代码

#include <bits/stdc++.h>
#define ll long long
#define N 1001
#define mod 998244353
#define sortu(a) sort(a.begin(), a.end())
#define uniqueu(a) a.erase(unique(a.begin(), a.end()), a.end())
using namespace std;
mt19937_64 mrand(random_device{}());

const int D[4][2] = {{0, 1}, {1, 0}, {-1, 0}, {0, -1}};

int n, m, d;
char s[N][N];
int dist[N][N];

inline void bfs(void) {
	queue<pair<int, int>> q;
	memset(dist, -1, sizeof(dist));
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= m; j++)
			if (s[i][j] == 'H') {
				dist[i][j] = 0;
				q.push({i, j});
			}
	for ( ; !q.empty(); ) {
		int x = q.front().first, y = q.front().second;
		q.pop();
		for (int i = 0; i < 4; i++) {
			int xx = x + D[i][0], yy = y + D[i][1];
			if (xx < 1 || yy < 1 || xx > n || yy > m || s[xx][yy] == '#' || dist[xx][yy] != -1)
				continue;
			dist[xx][yy] = dist[x][y] + 1;
			q.push({xx, yy});
		}
	}
}

int main() {
	scanf("%d%d%d", &n, &m, &d);
	for (int i = 1; i <= n; i++)
		scanf("%s", s[i] + 1);
	bfs();
	int ans = 0;
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= m; j++)
			if (dist[i][j] <= d && dist[i][j] != -1)
				ans++;
	printf("%d\n", ans);
}

总结

多源BFS模板题。

posted @ 2024-12-08 11:17  笙竺  阅读(22)  评论(0)    收藏  举报