前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >HDU 1213 How Many Tables(并查集讲解)

HDU 1213 How Many Tables(并查集讲解)

作者头像
Ch_Zaqdt
发布2019-01-10 11:37:44
3420
发布2019-01-10 11:37:44
举报
文章被收录于专栏:Zaqdt_ACMZaqdt_ACM

       这是我写的第一道并查集的题,也应该是一道最简单的入门题了,所以就以这道题说下并查集,其实就是找关系,比如说这道题的题意就是有n个人聚餐,然后他们不一定都互相认识,如果a认识b,b认识c,那么就让他们仨坐一桌,再如果c认识d,d认识e,那么就让这三个人另外坐一桌,所以就是有关系的就坐一桌,然后问需要多少张桌子(忽略每张桌子能坐多少人)。 

       那么并查集就分为并和查两个过程, 首先我们需要开一个数组pre来记录,刚开始我们初始化为pre[i] = i,然后在输入数据的时候将他们有关系的都并起来,比如输入1和2,2和3,我们可以先查这些点的是不是独立的结点,如果是的话就把他们连起来,那么就是pre[2]=1,pre[3]=2,这里可以用一个路径压缩,来把3号的父节点改成1,这样更便于查找(压缩路径下面会说),那么现在就是pre[2]=1,pre[3]=1,这就是并的过程,而查的过程就是比如说你要查3号,然后pre[3]就是3号对应的根节点了。思路大概是这样的,具体的东西可以结合代码看一下。

       并查集呢也就是并和查两个部分,所以用两个函数Merge和Find(我习惯这么定义了),而查的过程中有很多种写法,可以用循环,也可以用递归,我看其他Dalao的博客写的都很详细,我也没有那么好的文采,所以这里就不详细的说了。先说一下没有路径压缩的写法,虽然路径压缩可以大大减短运行时间,但是有时候有些题它不压缩路径才能做。思路就是在一个while循环里不断的去查当前节点的父节点,直到x==pre[x]为止,最后的r就是你要查的x的根节点了。

代码语言:javascript
复制
int Find(int x){ 
  int r=x; 
  while(parent[r] !=r) 
     r=parent[r];
  return r; 
}

       然后说一下路径压缩的方法,路径压缩可以缩短程序运行时间,方法也分为递归方法和非递归方法,而递归方法有时候对于数据较大的程序来说会造成栈溢出,所以对于这种情况可以用非递归的方法,不太好理解,试着手动模拟一下就很好理解了。

代码语言:javascript
复制
int Find(int x){              // 非递归方法
    int k, j, r;
    r = x;
    while(r != parent[r])     // 查找跟节点
        r = parent[r];        // 找到跟节点,用r记录下
    k = x;
    while(k != r){
        j = parent[k];         // 用j暂存parent[k]的父节点
        parent[k] = r;        // parent[x]指向跟节点
        k = j;                    // k移到父节点
    }
    return r;
}

int Find(int x){                   // 递归方法
  if(x != pre[x]){
    pre[x] = Find(pre[x]);
  }
  return pre[x];
}

       然后是并的过程。

代码语言:javascript
复制
void merge(int x,int y){
  int fx = Find(x);         // 查找x的根节点
  int fy = Find(y);         // 查找y的根节点
  if(fx != fy){
    pre[fy] = fx;           // 合并
  }
}

      最后看一下开头说的那道题的代码吧,还不理解的就手动模拟一下。

AC代码:

代码语言:javascript
复制
#include <iostream>
#include <cstdio>
using namespace std;
const int MAXN = 1005;
int pre[MAXN];
int T,n,m;

void init(){
  for(int i=0;i<=n;i++){
    pre[i] = i;
  }
}

int Find(int x){
  if(x != pre[x]){
    pre[x] = Find(pre[x]);
  }
  return pre[x];
}

void merge(int x,int y){
  int fx = Find(x);
  int fy = Find(y);
  if(fx != fy){
    pre[fy] = fx;
  }
}

int main()
{
  scanf("%d",&T);
  while(T--){
    scanf("%d%d",&n,&m);
    init();
    for(int i=0;i<m;i++){
      int a,b;
      scanf("%d%d",&a,&b);
      merge(a,b);
    }
    int sum = 0;
    for(int i=1;i<=n;i++){
      if(i == pre[i]){
        sum++;
      }
    }
    printf("%d\n",sum);
  }
  return 0;
}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018年02月22日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
文件存储
文件存储(Cloud File Storage,CFS)为您提供安全可靠、可扩展的共享文件存储服务。文件存储可与腾讯云服务器、容器服务、批量计算等服务搭配使用,为多个计算节点提供容量和性能可弹性扩展的高性能共享存储。腾讯云文件存储的管理界面简单、易使用,可实现对现有应用的无缝集成;按实际用量付费,为您节约成本,简化 IT 运维工作。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档