UCV2013H - Slick题解

· · 题解

思路:

用并查集来维护连通块,可以快速查询每个连通块的大小。这时我们只需要向一个是石油的点的四周拓展,看那个点是不是石油。如果是,则加入到连通块中。最后,我们可以将所有联通块,按面积从小到大排序,再按题目格式输出即可。

code:

#include <bits/stdc++.h>
using namespace std;
void write(int x){
    if(x<0){
        putchar('-');
        x=-x;
    }
    if(x>9){
        write(x/10);
    }
    putchar(x%10+'0');
    return ;
}
int read(){
    int x=0,f=1;
    char ch=getchar();
    while(ch<'0' || ch>'9'){
        if(ch=='-')f=-1;
        ch=getchar();
    }
    while(ch>='0' && ch<='9'){
        x=(x<<1)+(x<<3)+(ch^48);
        ch=getchar();
    }
    return x*f;
}
int t,n,m,a[510][510],Father[510*510],siz[510*510],tot=0,cnt=0;
int calc(int x,int y){
    return (x-1)*m+y;
}
unordered_map<int,bool>ma; 
struct node{
    int area;
}ans[510*510];
void init(){
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            Father[calc(i,j)]=calc(i,j);
            siz[calc(i,j)]=1;
        }
    }
}
int find(int x){
    if(Father[x]!=x){
        Father[x]=find(Father[x]);
    }
    return Father[x];
}
void merge(int x,int y){
    if(x!=y){
        Father[y]=x;
        siz[x]+=siz[y];
    }
    return ;
}
bool cmp(const node &x,const node &y){
    return x.area<y.area;
}
int main(){
    while(1){
        n=read();
        m=read();
        if(n==0 && m==0)break;
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                a[i][j]=read();
            }
        }
        init();
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                if(a[i][j]==1 && a[i+1][j]==1 && i+1<=n){
                    merge(find(calc(i,j)),find(calc(i+1,j)));
                }
                if(a[i][j]==1 && a[i-1][j]==1 && i-1>=1){
                    merge(find(calc(i,j)),find(calc(i-1,j)));
                }
                if(a[i][j]==1 && a[i][j+1]==1 && j+1<=m){
                    merge(find(calc(i,j)),find(calc(i,j+1)));
                }
                if(a[i][j]==1 && a[i][j-1]==1 && j-1>=1){
                    merge(find(calc(i,j)),find(calc(i,j-1)));
                }
            }
        }
        ma.clear();
        cnt=0;
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                if(ma[find(calc(i,j))]==false && a[i][j]==1){
                    ma[find(calc(i,j))]=true;
                    ans[++cnt].area=siz[find(calc(i,j))];
                }
            }
        }
        sort(ans+1,ans+cnt+1,cmp);
        int la=-1;
        tot=0;
        ma.clear();
        cout<<cnt<<endl;
        for(int i=1;i<=cnt;i++){
            if(!ma[ans[i].area]){
                if(tot!=0){
                    write(tot);
                    puts("");
                }
                write(ans[i].area);
                printf(" ");
                tot=1; 
                ma[ans[i].area]=true;
            }
            else{
                ++tot;
            }
        }
        if(tot){
            write(tot);
            puts("");
        }
    }
    return 0;
}