xjoi题解:P8089 蜜蜂的家
时间:1s 空间:256M
题目描述:
有一个无限大的蜂窝,里面住着一些蜜蜂,如图。

蜜蜂的家是由若干个蜂窝里的六边形连接而成,一个六边形(i,j),与六边形(i−1,j−1),(i−1,j),(i,j−1),(i,j+1),(i+1,j),(i+1,j+1)相邻。
现在小信知道一些六边形上有蜜蜂,请你告诉小信共有多少个蜜蜂的家。
输入格式:
第一行包含一个整数 n,代表有蜜蜂的六边形个数。
接下来 n 行,每行两个整数 xi,yi,表示有蜜蜂的六边形坐标。保证不存在相同的坐标。
输出格式:
输出一个整数表示答案。
样例输入:
7
0 0
1 1
1 0
1 -1
0 2
3 2
3 1
样例输出:
3
约定:
对于100%的数据,1≤n≤1000,0≤|xi|,|yi|≤1000,保证坐标互不相同。
分析:
哇,六联通题!!!
我们先将有蜜蜂的坐标化为二维数组中0和1,有蜜蜂的位置为1,无蜜蜂的位置为0。
既然是求解蜜蜂的家的个数,自然先想到的办法就是先处理一个蜜蜂,然后处理下一个蜜蜂……然后依次计数蜜蜂的家的个数,也就是每次处理一个蜜蜂的家的时候+1。我们按照这种方法来实现。
与之前的选数字,或者是给出指定入口求解是否能走地图的题目不同。本题需要全部遍历地图,也就是说需要一个一个格子来遍历数组,采用双重的for循环来实现。试想一下:当某一个格子是1时候,我们就从这个格子开始进行bfs,bfs的目的是处理掉与1相连的所有的1,于此同时计数+1。处理完成后,找到下一个是1的格子,再处理掉与此相连的1,计数+1。如此往复,直到处理完整个地图,搜索结束。
那么不难看出,递归边界就是:这个格子在地图外边。进行递归的条件是:当且仅当这个格子是1并且还没有访问过。
还有一点别忘记,此题判定1相邻的条件是六向联通 也就是(i−1,j−1),(i−1,j),(i,j−1),(i,j+1),(i+1,j),(i+1,j+1)相邻也算联通,所以此题是六向搜索。
代码:
#include<bits/stdc++.h>
int xx1 = 1e9, yy1 = 1e9, xx2 = -1e9, yy2 = -1e9;
using namespace std;
int a[2100][2100];
int fx, fy, n, m, head = 1, tail = 0, ans;
int dx[4] = {-1, 1, 0, 0};
int dy[4] = {0, 0, -1, 1};
struct node {
int x;
int y;
} que[505];
void bfs() {
++tail;
que[tail].x = fx;
que[tail].y = fy;
ans++;
a[fx][fy] = 0;
while (head <= tail) { //队列不空
for (int i = 0; i < 4; i++) {
int tx = que[head].x + dx[i];
int ty = que[head].y + dy[i];
if (tx >= xx1 && tx <= xx2 && ty >= yy1 && ty <= yy2 && a[tx][ty] == 1) {
++tail;
que[tail].x = tx;
que[tail].y = ty;
ans++;
a[tx][ty] = 0;
}
}
head++;
}
}
int main() {
int n;
cin >> n;
for (int i = 1; i <= n; i++) {
int x, y;
cin >> x >> y;
a[1000 + x][1000 + y] = 1;
xx1 = min(xx1, x + 1000);
yy1 = min(yy1, y + 1000);
xx2 = max(xx2, x + 1000);
yy2 = max(yy2, y + 1000);
}
// cout<<xx1<<" "<<yy1<<" "<<xx2<<" "<<yy2<<" ";
for (int i = xx1; i <= xx2; i++) {
for (int j = yy1; j <= yy2; j++) {
//cout<<a[i][j]<<" ";
if (a[i][j] == 1) {
fx = i;
fy = j;
}
}
//cout<<endl;
}
bfs();
cout << ans;
return 0;
}