toj2469 Friends

来源:互联网 发布:淘宝一元秒杀活动 编辑:程序博客网 时间:2024/05/16 15:05

题目链接:http://acm.tju.edu.cn/toj/showp2469.html

题目大意:给定一些人,如果他们不是朋友,就不能住在一间房间。朋友间的关系是可以传递的,即A和B是朋友,B和C是朋友,那么A和C也是朋友。 给定人数和他们的关系,问至少需要多少个房间;

思路:画个示意图,瞬间发现是求连通分量个数的问题,直接并查集,最终连通分量的个数即为房间数。用并查集的关键在于实现以下几个函数:Make, Find, Union!下面copy一段关于并查集的定义和使用(如果你对并查集不熟的话,可以看看)

l         并查集:(union-find sets)

一种简单的用途广泛的集合并查集是若干个不相交集合,能够实现较快的合并和判断元素所在集合的操作,应用很多,如其求无向图的连通分量个数等。最完美的应用当属:实现Kruskar算法求最小生成树。

l         并查集的精髓(即上面讲的三种操作):

1、Make_Set(x) 把每一个元素初始化为一个集合

初始化后每一个元素的父亲节点是它本身,每一个元素的祖先节点也是它本身(也可以根据情况而变)。

2、Find_Set(x) 查找一个元素所在的集合

查找一个元素所在的集合,其精髓是找到这个元素所在集合的祖先!这个才是并查集判断和合并的最终依据。
判断两个元素是否属于同一集合,只要看他们所在集合的祖先是否相同即可。

合并两个集合,也是使一个集合的祖先成为另一个集合的祖先,具体见示意图

3、Union(x,y) 合并x,y所在的两个集合

合并两个不相交集合操作很简单:
利用Find_Set找到其中两个集合的祖先,将一个集合的祖先指向另一个集合的祖先。

l         并查集的优化

1、Find_Set(x)时 路径压缩
寻找祖先时我们一般采用递归查找,但是当元素很多亦或是整棵树变为一条链时,每次Find_Set(x)都是O(n)的复杂度,有没有办法减小这个复杂度呢?
答案是肯定的,这就是路径压缩,即当我们经过"递推"找到祖先节点后,"回溯"的时候顺便将它的子孙节点都直接指向祖先,这样以后再次Find_Set(x)时复杂度就变成O(1)了,如下图所示;可见,路径压缩方便了以后的查找。

2、Union(x,y)时 按秩合并
即合并的时候将元素少的集合合并到元素多的集合中,这样合并之后树的高度会相对较小。


结合本题的代码,你会有一个更加深刻的理解:

ps:在第二遍做这道题的时候, 犯了一个致命的细节错误,问题时测试用例还没有测出来, 因为数组下标表示的是人的标号  而人的标号是从1开始的  所以再循环时,标号不能从0开始!!

#include <iostream>
#include <cstring>
using namespace std;
struct people               //最近对数组无感  发现struct很好用的
{
    int ancestor;
}people[102];

int find(int i)                //!!关键 find 函数  不断通过 j=people[j].ancestor来找祖先
{
  int j = i;
  while(1)
  {
    if(people[j].ancestor == -1)
    {
       if(j!=i)
       people[i].ancestor = j;     //在返回祖先时别忘了把该节点的祖先设置为找到的祖先
       return j;
    }
    j = people[j].ancestor;
  }
}

int main()
{
  int cas;
  cin>>cas;
  while(cas--)
  {
    int n,i,m;
    cin>>n>>m;
    for(i=1;i<=n;i++)
    {
        people[i].ancestor=-1;   //关键 make函数 :初始化每个节点的祖先都是-1,在find函数中判断为-1时,返回祖先本身;
    }
     for(i=0;i<m;i++)
     {
        int a,b,x,y;
        cin>>a>>b;
        x = find(a);
        y = find(b);
        if(x!=y)
        {
        people[x].ancestor = y;  //关键 union函数: 如果两个节点的祖先不同,因为有朋友关系,所以把一个的祖先设置为另一个节点
        }
     }
     int ans = 0;
     for(i=1;i<=n;i++)            //下标从1开始啊 魂淡
     {
        if(people[i].ancestor == -1)    //多少个根  跟少个连通分量  即多少间房
        ans++;
     }
     cout<<ans<<endl;
  }
  return 0;
}






原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 联币金融跑路了怎么办 胃消化不了想吐怎么办 吃撑了恶心想吐怎么办 mac口红膏体晃动怎么办 excl图标和以前不一样了怎么办 冰箱显示板坏了怎么办 冰箱电脑显示屏坏了怎么办 冰箱的电子显示屏坏了怎么办 指导别人炒股亏损了怎么办 没有协议委托别人炒股亏损怎么办 炒股亏了很多钱崩溃了怎么办 帮人炒股亏了很多钱怎么办 破净买入继续跌怎么办 国画颜色上错了怎么办 宝宝5个月脸一直开裂怎么办 宝宝冻脸怎么办小妙招 3岁小儿长期便秘怎么办 脚裂了怎么办小妙招 宝宝脸风吹裂了怎么办 宝宝脸被风吹裂了怎么办 小宝贝的手有时候抖怎么办 打球把手戳肿了怎么办 阴茎上皮肤皴了怎么办 手皮肤干燥起皮怎么办 一到冬天手脚冰凉怎么办 脸上的皮肤被搓掉了怎么办 皮肤的表皮搓掉了怎么办 固体水彩经常掉出来怎么办 画水彩纸皱了怎么办 画完水彩纸皱了怎么办 旗袍后面隐形拉链气包怎么办 电动缝纫机不往前走怎么办 衬衣领子磨烂了怎么办 白寸衣领变黄怎么办 黑衣领衣服洗发黄怎么办 白毛衣用84变黄怎么办 白色貂毛衣变黄怎么办 蓝色T恤衣领汗積洗不掉怎么办 蓝色t恤衣领汗积洗不掉怎么办 羽绒服在衣柜里放黄了怎么办 白羽绒服放久了泛黄怎么办