H国正在进行一项持续N周的填海造岛工程。整片工程海域可以被看作是1000x1000的网格。
每周都有一块1x1的单位方格海域被填成陆地。如果我们将连成一片的陆地(一块单位方格与它上下左右4个单位方格是相连的)视为岛屿,H国想监测每周末整片海域中一共存在有多少个岛屿,以及这些岛屿的总面积和总周长各是多少。
假设工程持续三周,第一周被填的海域坐标是(0, 0),那么第一周结束后有1座岛屿、总面积是1、总周长是4:
#.. ... ...
第二周被填的海域坐标是(1, 1),那么第二周结束后有2座岛屿、总面积是2、总周长是8:
#.. .#. ...
第三周被填的海域坐标是(1, 0),那么第三周结束后有1座岛屿、总面积是3、总周长是8:
#.. ##. ...
你能完成这项任务么?
第一行包含一个整数N,表示工程持续的周数。(1 <= N <= 100000)
以下N行每行包含两个整数x和y,表示当周被填的海域坐标。(0 <= x, y < 1000)
输出N行,每行包含3个整数,依次是当周末岛屿的数量、总面积和总周长。
3 0 0 1 1 1 0
1 1 4 2 2 8 1 3 8
思路:要求三个量,岛屿数目、面积、周长;面积最好求,多一个方格就+1,周长的话多一个方格就先加上4,然后每与一个方格相邻就减4。最难求的是岛屿数目,一开始以为用dfs,但其实是用并查集。这里有个小技巧,就是要把二维数组映射到一维数组,公式是1000*x+y。
代码如下:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int a[1005][1005];
int n;
int len=0;
int square=0;
int cnt=0;
int pre[1000005];
int dx[4]= {-1,0,1,0};
int dy[4]= {0,-1,0,1};
int find(int x)
{
int r=x;
while(pre[r]!=r)
r=pre[r];
int i=x;
int j;
while(i!=r)//路径压缩
{
j=pre[i];
pre[i]=r;
i=j;
}
return r;
}
void join(int x,int y)
{
int fx=find(x);
int fy=find(y);
if(fx!=fy)
pre[fy]=fx;
}
int main()
{
scanf("%d",&n);
memset(a,0,sizeof(a));
int x,y;
for(int i=0; i<1000005; i++)
pre[i]=i;
for(int i=0; i<n; i++)
{
scanf("%d%d",&x,&y);
a[x][y]=1;
len+=4;
square++;
cnt++;
int x_;
int y_;
for(int i=0; i<4; i++)
{
x_=x+dx[i];
y_=y+dy[i];
if(x_<0||x_>=1000||y_<0||y_>=1000||a[x_][y_]==0)
continue;
else
{
if(a[x_][y_])
{
int xx=find(x*1000+y);
int yy=find(x_*1000+y_);
if(xx!=yy)
{
cnt--;
join(xx,yy);
}
len-=2;
}
}
}
printf("%d %d %d\n",cnt,square,len);
}
}
最后唠叨一下,因为敲的时候把并查集的模板敲错了,所以一直wa。。。看来功力不够深厚啊。。。