传送门
方法就是在同一行的是一个集合,在同一列的也是一个集合,先存再一个一个枚举即可。
这里主要就是要注意,当所有的点都已经全部连接完毕之后,编号为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;
}
来源:https://blog.csdn.net/weixin_44781226/article/details/102779213