刷题日记2024_1_31
原题链接:
1098. 城堡问题 - AcWing题库
题目分析:
不难看出,这道题其实也是一个求连通块的问题。比较不同的点是这个题目的输入数据稍微复杂一点。每一个元素代表一个房间四周墙的分布情况(1代表西墙0001,2代表北墙0010 ,4代表东墙0100, 8代表南墙1000)(再比如11代表西墙、北墙、南墙 1011)由此可以看出,我们可以利用二进制数的思想,来判断一个房间四周是否有墙(是否连通)。
即
if (mp[t.x][t.y] >> i & 1)
continue;
意思是,如果把某个房间的元素左移 i 位并 与 1 ,就可以知道第 i 位数(从低位往高位数)是1 还是 0。如果是1 就说明 这个方向是有墙的,0就说明没有墙。
下面看对每个元素(房间)是如何进行bfs 操作的:
我们按照题目上给出的顺序来(0123 分别代表西北东南)。
那么dx[]
, dy[]
数组的顺序也随之确定了。(dx,dy数组是表示某元素的相邻的四个方向的元素)
当下标为 0 时,表示西墙 – > dx[0]=0
,dy[0]=-1
。(因为x表示行方向,y表示列方向,所以当dx=0,dy=1时,坐标会往左移一位,也就是往西移动)
#define x first
#define y second
typedef pair<int, int> PII;
int mp[N][N];
PII q[M];
bool st[N][N];
int dx[4] = { 0,-1,0,1 }; //注意这里的dx[],dy[]
int dy[4] = { -1,0,1,0 };
int bfs(int sx, int sy)
{
int hh = 0, tt = 0;
q[0] = { sx,sy };
st[sx][sy] = 1; //把队头元素标记为1
int ans = 0;
while (hh <= tt)
{
PII t = q[hh++];
ans++; //每加入队列一个元素就要ans++
for (int i = 0; i < 4; i++)
{
int xx = t.x + dx[i];
int yy = t.y + dy[i];
if (xx <= 0 || xx > n || yy <= 0 || yy > m)
continue;
if (st[xx][yy] == 1)
continue;
if (mp[t.x][t.y] >> i & 1) //这里就是判断某个房间的四个方向是否有墙,如果有墙就不能连通,要continue
continue;
q[++tt] = { xx,yy };
st[xx][yy] = 1;
}
}
return ans;
}
下面是完整代码:
#include<bits/stdc++.h>
#define x first
#define y second
using namespace std;
typedef pair<int, int> PII;
const int N = 100,M=N*N;
int n, m;
int mp[N][N];
PII q[M];
bool st[N][N];
int dx[4] = { 0,-1,0,1 };
int dy[4] = { -1,0,1,0 };
int bfs(int sx, int sy)
{
int hh = 0, tt = 0;
q[0] = { sx,sy };
st[sx][sy] = 1;
int ans = 0;
while (hh <= tt)
{
PII t = q[hh++];
ans++;
for (int i = 0; i < 4; i++)
{
int xx = t.x + dx[i];
int yy = t.y + dy[i];
if (xx <= 0 || xx > n || yy <= 0 || yy > m)
continue;
if (st[xx][yy] == 1)
continue;
if (mp[t.x][t.y] >> i & 1)
continue;
q[++tt] = { xx,yy };
st[xx][yy] = 1;
}
}
return ans;
}
int main()
{
cin >> n >> m;
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
cin >> mp[i][j];
}
}
int cnt = 0, ans = 0;
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
if (!st[i][j])
{
ans = max(ans, bfs(i, j));
cnt++;
}
}
}
cout << cnt << endl;
cout << ans << endl;
return 0;
}