传送门
方法就是在同一行的是一个集合,在同一列的也是一个集合,先存再一个一个枚举即可。
这里主要就是要注意,当所有的点都已经全部连接完毕之后,编号为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