hiho 1487 并查集+搜索 [Offer收割]编程练习赛11 problem C 岛屿3

#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 


题意非常简单,1000*1000的矩阵,一开始是空的,每次不重复的放一个点,求4向联通集的个数,总面积和总周长。

这里联通集我们用并查集处理一下,二维的点集,可以把x,y映射到1000x+y上构成一维的。因为xy范围都在1000内,用并查集以便于统计联通集的个数,每次放入一个新块之后,把周边的相邻的点都先存到一个vector里,然后挨着判断一下是不是一个集合,如果不是一个集合,那么联通集总数就要-1,如果不相邻,总数就+1,新增周长可以用4-2*相邻的边数来计算。


这个题调试了半天,2.30比赛结束,我2.31提交上去1A了,T_T。问题出在我这一堆for循环上,有一个地方手抖敲错了。。。for(int k=0;k<4;i++),我调了将近半个小时,就是没看出来哪里不对,程序运行到这就卡住了,比赛结束的一瞬间我把i改成k交上去就A了。天命如此……自己太水,不想说什么了,这又让我想起来几次区域赛打铁的经历,跟这次大同小异,有毒呀。





#include <iostream>
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <string>
#include <string.h>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <stack>
using namespace std;


//x*1000+y;
int par[1000005];
int tall[1000005];
void init(int n){
    for(int i=1;i<=n;i++){
        par[i]=i;
        tall[i]=0;
    }
}

int find_root(int x){
    if(par[x]==x){
        return x;
    }
    else{
        return par[x]=find_root(par[x]);
    }
}

void unite(int x,int y){
    x=find_root(x);
    y=find_root(y);
    if(x==y)return;
    if(tall[x]<tall[y]){
        par[x]=y;
    }
    else{
        par[y]=x;
        if(tall[x]==tall[y])tall[x]++;
    }
}

bool same(int x,int y){
    return find_root(x)==find_root(y);
}




int F[1005][1005];

int d[4][2]={1,0,0,1,0,-1,-1,0};
int n;
bool cango(int x,int y){
    return x>=0&&x<1000&&y>=0&&y<1000;
}

int main()
{
    while(cin>>n){
        memset(F,0,sizeof(F));
        init(1000009);
        int num=0;//数量
        int S=0;//面积
        int L=0;//周长
        for(int i=0;i<n;i++){
            int x,y;
            scanf("%d%d",&x,&y);
            F[x][y]=1;
            int V=x*1000+y+1;
            int find_a_new=1;//四周都是空的
            int chongbian=0;//重合边数量
            vector<int>P;//所有边界点
            P.clear();
            for(int k=0;k<4;k++){
                int nx=x+d[k][0];
                int ny=y+d[k][1];

                if(cango(nx,ny)){
                    int nV=nx*1000+ny+1;
                    if(F[nx][ny]==1){
                        P.push_back(nV);
                        chongbian++;
                        find_a_new=0;//没找到新的
                        if(same(nV,V)){
                            //chongbian++;
                            //unite(nV,V);
                        }
                        else{
                            //unite(nV,V);
                            //chongbian++;
                        }
                    }
                    else{

                    }
                }

                else{

                }
               // cout<<"fuck"<<endl;



            }
            if(find_a_new==1){
                num++;
                L+=4;
            }
            else{
                unite(P[0],V);
               // cout<<"stat "<<P.size()<<endl;
                //cout<<P[0]<<" !!! "<<P[1]<<endl;
                for(int j=1;j<P.size();j++){
                    if(!same(P[j],P[j-1])){
                        num--;
                        unite(P[j],P[j-1]);
                    }
                }
               // cout<<"stat2"<<endl;
                L+=4-2*chongbian;
            }

            S++;
            cout<<num<<" "<<S<<" "<<L<<endl;

        }

    }
    return 0;
}





  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值