[Offer收割]编程练习赛11 1487 岛屿3
时间限制:10000ms
单点时限:1000ms
内存限制:256MB
描述
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
面积和周长都很简单, 就是岛屿的数量比较麻烦。可以用并查集,对于n个岛屿,经过合并后剩下岛屿的数量等于n减去合并次数。
代码如下:
#include<bits/stdc++.h>
using namespace std;
const int N = 1070;
int par[1010*1010], Rank[1010*1010];
char mp[1007][1007];
int dir[4][2] = { {1, 0}, {-1, 0}, {0, 1}, {0, -1}};
int many = 0;
void init()
{
memset(mp, '.', sizeof(mp));
for(int i=0; i<1010*1010; ++ i)
par[i] = i, Rank[i] = 0;
}
int Find(int x)
{
if(x == par[x])
return x;
return par[x] = Find(par[x]);
}
void unite(int x, int y)
{
x = Find(x), y = Find(y);
if(Rank[x] > Rank[y])
par[y] = x;
else
{
par[x] = y;
if(Rank[x] == Rank[y])
Rank[y] ++;
}
}
int solve(int x, int y)
{
mp[x][y] = '#';
int res = 0;
for(int i=0; i<4; ++ i)
{
int s = x + dir[i][0], t = y + dir[i][1];
if(s >= 0 && t >= 0 && mp[s][t] == '#')
{
if(Find(s*1005+t) != Find(x*1005+y))
{
many ++;
unite(s*1005+t, x*1005+y);
}
res ++;
}
}
if(res == 0)
return 4;
if(res == 1)
return 2;
if(res == 2)
return 0;
if(res == 3)
return -2;
if(res == 4)
return -4;
}
int main()
{
ios::sync_with_stdio(false);
init();
int n;
cin >> n;
int g = 0;
for(int i=1; i<=n; ++ i)
{
int x, y;
cin >> x >> y;
g += solve(x, y);
cout << i-many << " " << i << " " << g << endl;
}
return 0;
}