并查集

并查集
并查集,在一些有N个元素的集合应用问题中,我们通常是在开始时让每个元素构成一个单元素的集合,然后按一定顺序将属于同一组的元素所在的集合合并,其间要反复查找一个元素在哪个集合中。这一类问题近几年来反复出现在信息学的国际国内赛题中,其特点是看似并不复杂,但数据量极大,若用正常的数据结构来描述的话,往往在空间上过大,计算机无法承受;即使在空间上勉强通过,运行的时间复杂度也极高,根本就不可能在比赛规定的运行时间(1~3秒)内计算出试题需要的结果,只能用并查集来描述。
(百度百科)
例题
小郑作为新生,刚刚来到美丽的比斯猪,学校规定每见到一个陌生人都要上去握手并成为好朋友,但为了避免把全校同学手都握了,学校还规定只要遇见一个陌生人,如果这个陌生人是他朋友认识的,那就是自己认识的,就不和她握手(朋友的朋友就是我的朋友,只要是能通过朋友关系串联起开,不管多远,都不握手)
这样问题就来了,因为学校里的同学实在太多了,如果要一个个问朋友认不认识这个人,再问朋友的朋友认不认识那个人。这样问下来一整天也不一定能够知道这个人自己到底认不认识。

int person[100];
int find(int root)//查找认识的最远的人
{
int son = root;
 while(root != person[root])//先找出认识的最远的人(根节点) 
  root  = person[root];
   while(son != root)
 {
  int temp = person[son];//先用temp保存自己认识的人 
  person[son] = root;//让自己直接认识最远的人(根节点) 
  son = temp;//再让自己变成temp里原来认识的人 
 }
 return root;
}
bool shakeHand(int x,int y)
{
 x = find(x);//查找x认识的最远的人 (根节点)
 y = find(y);//查找y认识的最远的人 (根节点)
 if(x!=y)//如果认识的人不相同,那么就握手
 {
  person[x] = y;//让x的根节点认识y的根节点
  return true;
 }
 return false;
  
} 
int main()
{
 int n;//一共n个人
 scanf("%d",&n);
 for(int i=1;i<=n;i++)
  person[i] = i;//所有人都认识自己
 int m;//一共m次握手 
 scanf("%d\n",&m);
 int total = 1;//每个人最多认识一个人 
 while(m--)
 {
  int x,y;
  scanf("%d %d",&x,&y);
  if(shakeHand(x,y))//x和y握手成功
   total++; 
 }
 if(total == n)
  printf("所有人都互相认识了\n");
 else
  printf("还有人没有认识");
 return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值