这是一道模板题,因此我们把基础概念捋清,本题就水到渠成。并查集是跟图,树相关的一种算法。首先了解一下什么叫图:在数学中,图是描述于一组对象的结构,其中某些对象对在某种意义上是“相关的”。这些对象对应于称为顶点的数学抽象(也称为节点或点),并且每个相关的顶点对都称为边(也称为链接或线)。通常,图形以图解形式描绘为顶点的一组点或环,并通过边的线或曲线连接。 图形是离散数学的研究对象之一。——FROM百度百科。从图的定义中我们可以得知,图就是一些相关的元素组成的集合,因此自然与并查集有关了。“并”自然指的是合并,而“查"就是指查找,”集“就是指集合了。另外,树这种数据结构也是我们了解并查集必备的知识,就不讲解了。合并是需要树的,因为不同的集合推举出来某个根,在合并的时候根与根还要有依附的关系,路径压缩也需要根的知识。我们借助本题看看并查集的本质。加注释的行列是我之前的错误想法,有启发思维和借鉴的意义,所以我没删,我由此进一步说明并查集的本质。在注释中有”认爹“等词语,是我在网上看的别人的武侠风格的讲解并查集的帖子,很有意思,与代码结合可以加深理解。还有按秩合并,我这个蒟蒻尚且没看代码实现,只说路径压缩吧。。。
另:并查集的核心函数就是find merge

#include<stdio.h>
#include<iostream>
#include<string>
#include<string.h>
#include <algorithm>
#include <cstdio>
using namespace std;
int a[2000];
//int a1[2000];
int b[2000];
//int e[2000];
//int f[2000];
int p[2000];
 int find(int x)//查找+路径压缩。 find函数的本质是找祖宗(根)的过程。
     {
         if(p[x]==x)return x;//这就是最原始的根了,找到了,找到了(尖叫状)
         else return p[x]=find(p[x]);//他爹=他祖宗,直接一步到位! 有啥好处呢,下一次查询的时候多快啊,一下子就把他爹(祖宗)揪出来了,方便比较。(这里用到递归,我们可以多从功能层面去关注,p[x]相当于他爹,find函数是找祖宗)
     }
     void merge(int x,int y)
     { 
         int m,n;
         m=find(x);
         n=find(y);
         if(m!=n)p[find(x)]=find(y);//祖宗的依附过程,y的祖宗变成了x祖宗的爹,.1的本质
     }
 int main()
{
    int jilu,j,t,w,k,cnt=0;
    cin>>t;
    int z;
    w=0;
    for(z=0;z<t;z++)
    {
        cin>>a[z]>>b[z];
//        a1[z]=a[z];
        p[z]=z;
    }
//        for(k=0;k<t-1;k++)//这一段碎碎念可以自动略过。。我错误的根源其实就是不理解.1的本质:祖宗依附,而我先前以为是单一元素的依附,还想用排序来解决,行不通,还在认错爹认新爹乱认爹那里纠结,还想特殊标记操作。。。耗了我数个小时,屡次有问同学的冲动,幸好没问,我当时真是傻的可以。。所以冲动之前一定要三思啊,尽量别问,若问了就是唐氏!
//        {    jilu=k;
//            for(j=k+1;j<t;j++)
//            {
//                if(a[j]<a[k])
//                {
//                swap(a[j],a[k]);
//                jilu=j;
//                }
//            }
//            e[w]=a1[jilu];
//            f[w]=b[jilu];
//            w++;
//        }
        for(k=0;k<t-1;k++)
        {
            for(j=k+1;j<t;j++)
        {
            if(a[k]==a[j]||b[k]==b[j])
            {
                merge(k,j);
            }    
        }
        }
        for(k=0;k<t;k++)
    {
        if(p[k]==k)cnt++;//让他们自己当自己爹。
    }//每个点都是独立的,有t个图。
    cout<<cnt-1<<endl;//cnt个图需要cnt-1个点给他们串起来
system("pause");
return 0;
 } 

总之,在代码实现新奇算法的旅通中,总会有各种各样的惊吓和惊喜,而没有人可以代替你领略这番风光。