P1457 [USACO2.1] 城堡 The Castle 题解

发布时间 2023-10-11 21:39:35作者: Manipula

分析

感觉没有蓝题难度

一道 bfs 题目,相较于大部分 bfs 题,它较为复杂,但分析一下还是很好水过的。

建立墙时,可以用三维数组,\(wall_{~i, ~j, ~pos}\) 表示 第 \(i\) 行第 \(j\)\(pos\) 方向有墙。

观察发现,\(8 = 2^3,4 = 2^2,2 = 2^1,1 = 2^1\),于是可以用位运算快速储存。这里给出代码方便理解。

void build(int x, int y, int w)
{
	if (w & 8)wall[x][y][0] = 1;
	if (w & 4)wall[x][y][1] = 1;
	if (w & 2)wall[x][y][2] = 1;
	if (w & 1)wall[x][y][3] = 1;
}

接下来就是 bfs 的过程,在 bfs 时,保存下答案,以及这个房间的编号和这个房间的大小,对于接下来的拆墙有用。

对于拆墙,前面保存的编号和房间大小有了作用,遍历行和列,并只看东墙和北墙,如果墙后与当前格子的编号相同,直接跳过,否则更新答案。

注意:遍历时先遍历列,再遍历行,然后选择北墙,最后是东墙,因为题目说明西边的更优,然后是更南的,最后同一格子下,北边的更优,详细的可以看代码说明。

Accepted Code

/*Code By Manipula*/
#include <bits/stdc++.h>
using namespace std;
const int N = 55;
int mp[N][N], wall[N][N][4], space[N], num, ans1, ans2, ax, ay, n, m;
int fx[4] = {1, 0, -1, 0}, fy[4] = {0, 1, 0, -1};
char dir;
void build(int x, int y, int w)
{
	if (w & 8)wall[x][y][0] = 1;
	if (w & 4)wall[x][y][1] = 1;
	if (w & 2)wall[x][y][2] = 1;
	if (w & 1)wall[x][y][3] = 1;
}
struct Node{
	int x, y;
};
queue<Node> q;
void bfs(int sx, int sy)
{
	q.push((Node){sx, sy});
	mp[sx][sy] = ++num;//记编号
	int ret = 1;
	while (!q.empty())
	{
		int x = q.front().x, y = q.front().y; q.pop();
		for (int i = 0; i < 4; i++)
		{
			int xx = x + fx[i], yy = y + fy[i];
			if (xx < 1 || xx > n || yy < 1 || yy > m)continue;
			if (mp[xx][yy] || wall[x][y][i])continue;
			mp[xx][yy] = num;
			q.push((Node){xx, yy});
			ret++;
		}
	}
	ans1 = max(ans1, ret);
	space[num] = ret;
}
int main()
{
	cin >> n >> m; n ^= m ^= n ^= m;//交换一下,个人喜欢 n 为行数, m 为列数
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= m; j++)
		{
			int w; cin >> w;
			build(i, j, w);
		}
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= m; j++)
			if (!mp[i][j])bfs(i, j);
	for (int j = 1; j <= m; j++)//选择最西的
		for (int i = n; i >= 1; i--)//选择最南的
			for (int pos = 2; pos >= 1; pos--)//优先选择北边的墙
				if (wall[i][j][pos])
				{
					int xx = i + fx[pos], yy = j + fy[pos];
					if (mp[i][j] == mp[xx][yy])continue;//特判,如果他们的编号相同就不计算
					if (space[mp[i][j]] + space[mp[xx][yy]] > ans2)
					{
						ans2 = space[mp[i][j]] + space[mp[xx][yy]];
						ax = i; ay = j; dir = (pos == 1 ? 'E' : 'N');
					}
				}
	cout << num << endl << ans1 << endl;
	cout << ans2 << endl << ax << " " << ay << " " << dir;
	return 0;
}