hiho一下183周 Counting Island II
题目原文
-
3 0 0 1 1 1 0
样例输出
-
1 2 1
Country H is going to carry out a huge artificial islands project. The project region is divided into a 1000x1000 grid. The whole project will last for N weeks. Each week one unit area of sea will be filled with land.
As a result, new islands (an island consists of all connected land in 4 -- up, down, left and right -- directions) emerges in this region. Suppose the coordinates of the filled units are (0, 0), (1, 1), (1, 0). Then after the first week there is one island:
#...
....
....
....
After the second week there are two islands:
#...
.#..
....
....
After the three week the two previous islands are connected by the newly filled land and thus merge into one bigger island:
#...
##..
....
....
Your task is track the number of islands after each week's land filling.
输入
The first line contains an integer N denoting the number of weeks. (1 ≤ N ≤ 100000)
Each of the following N lines contains two integer x and y denoting the coordinates of the filled area. (0 ≤ x, y < 1000)
输出
For each week output the number of islands after that week's land filling.
题意分析
向坐标点0<=x<1000,0<=y<1000的位置放置land,每个星期放置一个,输入总的星期数以及每个星期放入land的坐标,输出每周放置完之后孤立岛的个数。
解法分析
本题是一个典型并查集问题,对于每周加入的点,首先让res加一,需要查它上下左右四个点,如果有点已经变成land,且属于某个island(集合),则将新加入的点并入该集合,修改其parent,res减一。遍历到下一个邻点,如果他们的root相同,则再次并为一个集合,同时res减一,直到遍历完所有四个邻点。当然,如果root相同则不需要做任何操作,如果周边点不是land(记录每一个点的count,只要加入为land就为1,在并的过程中也需要将count小的并入大的),即count=0,则不进行任何操作,同时注意周边点的坐标不能越界。C++代码如下:
#include<iostream>
#include<unordered_map>
#include<string>
#include<vector>
#include<utility>
#include<cstring>
using namespace std;
pair<int,int> myFind(int x,int y,vector<vector<pair<int,int>>> &parent){
if(parent[x][y]==make_pair(x,y))
return parent[x][y];
else
return myFind(parent[x][y].first,parent[x][y].second,parent);
}
int main(){
vector<vector<pair<int,int>>> parent(1000,vector<pair<int,int>>(1000,make_pair(0,0)));
int i,j;
for(i=0;i<1000;i++){
for(j=0;j<1000;j++)
parent[i][j]=make_pair(i,j);
}
vector<vector<int>> count(1000,vector<int>(1000,0));
int N;
cin>>N;
int x,y;
int res=0;
pair<int,int> root1,root2;
int x1[4]={-1,1,0,0};//the four directions
int y1[4]={0,0,-1,1};
while(N>0){
cin>>x>>y;
res++;
count[x][y]=1;//this is a land
for(i=0;i<4;i++)
{
if((x+x1[i])>=0&&(x+x1[i])<1000&&(y+y1[i])>=0&&(y+y1[i])<1000&&count[x+x1[i]][y+y1[i]]>0)
{
root1=myFind(x,y,parent);
root2=myFind(x+x1[i],y+y1[i],parent);
if(root1!=root2)//if root1==root2,just continue;
{
res--;
if(count[root1.first][root1.second]>count[root2.first][root2.second])
{
count[root1.first][root1.second]+=count[root2.first][root2.second];
parent[root2.first][root2.second]=make_pair(root1.first,root1.second);
}
else
{
count[root2.first][root2.second]+=count[root1.first][root1.second];
parent[root1.first][root1.second]=make_pair(root2.first,root2.second);
}
}
}
}
cout<<res<<endl;
N--;
}
return 0;
}
代码中遍历四个邻点用了x1,y1两个数组,简化代码。parent用的二维vector,不可以直接定义parent[1000][1000],这样会造成栈溢出,可以用new放入堆中。这里还可以将坐标x,y用1000x+y转化为一个数,则只需要用一维数组。