任意点------并查集

一世执手 提交于 2019-12-02 15:22:03

传送门
方法就是在同一行的是一个集合,在同一列的也是一个集合,先存再一个一个枚举即可。

这里主要就是要注意,当所有的点都已经全部连接完毕之后,编号为i的点的祖先并不是fa[i],而是fin(i),因为最后还要进行一次预处理,将所有的点都重新整合一遍(防止出现类似于,1,2,3,4,5是一个集合,那么可能fa[1]=1,fa[2]=1,fa[3]=2,fa[4]=3,fa[5]=3这种情况)

#include<bits/stdc++.h>
using namespace std;
const int MX=1e3+9;
int n,fa[MX],pos[MX];
vector<int> vh[MX],vl[MX];

int fin(int u){
    return fa[u]=(fa[u]==u?u:fin(fa[u]));
}

void link(int u,int v){
    u=fin(u);
    v=fin(v);
    if( u!=v ){
        if( u<v )
            fa[v]=u;
        else
            fa[u]=v;
    }
}

int main()
{
   // freopen("input.txt","r",stdin);
    scanf("%d",&n);
    int hang,lie;
    for( int i=1 ; i<=n ; i++ ){
        scanf("%d %d",&hang,&lie);
        vh[hang].push_back(i);
        vl[lie].push_back(i);
        fa[i]=i;
    }
    for( int i=1 ; i<=1000 ; i++ ){
        if( vh[i].size()>1 )
            for( int j=1 ; j<vh[i].size() ; j++ )
                link(vh[i][j-1],vh[i][j]);
    }
    for( int i=1 ; i<=1000 ; i++ ){
        if( vl[i].size()>1 )
            for( int j=1 ; j<vl[i].size() ; j++ )
                link(vl[i][j-1],vl[i][j]);
    }
    memset(pos,0,sizeof(pos));
    int ans=0;
    for( int i=1 ; i<=n ; i++ )
        pos[fin(i)]=1;
    for( int i=1 ; i<=n ; i++ )
        if( pos[i] )
            ans++;
    printf("%d\n",ans-1);
    return 0;
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!