当前位置:首页 > > 充电吧
[导读]并查集Union-Find Set或Disjoint Set(不相交集合),将编号分别为1…N的N个对象划分为不相交集合,在每个集合中,选择其中某个元素代表所在集合。常见的操作合并两个集合;将一元素并

并查集

Union-Find Set或Disjoint Set(不相交集合),将编号分别为1…N的N个对象划分为不相交集合,在每个集合中,选择其中某个元素代表所在集合。

常见的操作

合并两个集合;将一元素并入另一集体;判断两个元素是否属于同一个集合;每个集合用一棵“有根树”表示.

实现方法 每个集合用一棵“有根树”表示,定义数组 set[1..n],set[i] = i , 则i表示本集合,并是集合对应树的根,set[i] = j, j!=i, 则 j 是 i 的父节点.
树形结构,只需记录每个结点的父结点即可,每棵树表示一个集合,树的根作为集合的“代表元”。
对于查找操作,实际上沿着父指针,向上找到根即可
对于合并操作:只要把一个集合的根节点和另一个集合连接就可以了。
判断是否属于同一个集合的方法:由此用某个元素所在树的根结点表示该元素所在的集合,判断两个元素时候属于同一个集合的时候,只需要判断他们所在树的根结点是否一样
即可也就是说,当我们合并两个集合的时候,只需要在两个根结点之间连边即可

HDOJ 1232 Problem Description
某省调查城镇交通状况,得到现有城镇道路统计表,表中列出了每条道路直接连通的城镇。省政府“畅通工程”的目标是使全省任何两个城镇间都可以实现交通(但不一定有直接的道路相连,只要互相间接通过道路可达即可)。问最少还需要建设多少条道路?
测试输入包含若干测试用例。每个测试用例的第1行给出两个正整数,分别是城镇数目N ( < 1000 )和道路数目M;随后的M行对应M条道路,每行给出一对正整数,分别是该条道路直接连通的两个城镇的编号。为简单起见,城镇从1到N编号。
注意:两个城市之间可以有多条道路相通,也就是说  3 3    1 2    1 2    2 1   这种输入也是合法的
当N为0时,输入结束,该用例不被处理。 对每个测试用例,在1行里输出最少还需要建设的道路数目。
地图上若干城镇都可以看作点,已知哪些对城镇之间是有道路直接相连的。最后要解决的是整幅图的连通性问题,即求整幅图一共有几个连通分支,也就是被分成了几个互相独立的块。 畅通工程这题,问还需要修几条路,实质就是求有几个连通分支。如果是1个连通分支,说明整幅图上的点都连起来了,不用再修路了;如果是2个连通分支,则只要再修1条路,从两个分支中各选一个点,把它们连起来,那么所有的点都是连起来的了;如果是n个连通分支,则只要再修n-1条路。

#include#define M 1000
int F[M];//并查集的根节点保存的数组
void Init(int *F)//初始化
{
    int i=0;
    for(i=0;i<M;i++)
        F[i]=i;
}
int find(int x)//查找元素所在的集合
{
    while(F[x]!=x)
    {
       x=F[x];
    }
    return x;
}
void Union(int u, int v)
{
	int s1 = find(u), s2 = find(v);
	if (s1 != s2) F[s1] = s2;
}
int main()
{
    int n,m;//城镇数目n和道路数目m
    int m_a,m_b;//m行测试数据的对应的两个数据,表示城镇ma和mb之间联通
    int i,count=0;
    freopen("input.txt","r",stdin);
    while(scanf("%d %d",&n,&m))
    {
        count=0;
        if(n==0)
        break;
        Init(F);
        while(m--)
        {
            scanf("%d %d",&m_a,&m_b);//把两个节点结合起来
            Union(m_a,m_b);
        }
        for(i=1;i<=n;i++)
        {
            if(F[i]==i)
            {
                count++;
            }
        }
        printf("%dn",count-1);//因为如果全部连接起来的话,根节点的还是会有i还是满足i=F[i]的。
    }
}


优化——路径压缩
思想:每次查找的时候,如果路径较长,则修改信息,以便下次查找的时候速度更快。
第一步,找到根结点 第二步,修改查找路径上的所有节点,将它们都指向根结点



带路径压缩的查找算法

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)       //查找x元素所在的集合,回溯时压缩路径
{
    if (x != parent[x])
    {
        parent[x] = find(parent[x]);     //回溯时的压缩路径
    }         //从x结点搜索到祖先结点所经过的结点都指向该祖先结点
    return parent[x];
}
//采用递归的方式压缩路径, 但是,递归压缩路径可能会造成溢出栈










本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: 驱动电源

在工业自动化蓬勃发展的当下,工业电机作为核心动力设备,其驱动电源的性能直接关系到整个系统的稳定性和可靠性。其中,反电动势抑制与过流保护是驱动电源设计中至关重要的两个环节,集成化方案的设计成为提升电机驱动性能的关键。

关键字: 工业电机 驱动电源

LED 驱动电源作为 LED 照明系统的 “心脏”,其稳定性直接决定了整个照明设备的使用寿命。然而,在实际应用中,LED 驱动电源易损坏的问题却十分常见,不仅增加了维护成本,还影响了用户体验。要解决这一问题,需从设计、生...

关键字: 驱动电源 照明系统 散热

根据LED驱动电源的公式,电感内电流波动大小和电感值成反比,输出纹波和输出电容值成反比。所以加大电感值和输出电容值可以减小纹波。

关键字: LED 设计 驱动电源

电动汽车(EV)作为新能源汽车的重要代表,正逐渐成为全球汽车产业的重要发展方向。电动汽车的核心技术之一是电机驱动控制系统,而绝缘栅双极型晶体管(IGBT)作为电机驱动系统中的关键元件,其性能直接影响到电动汽车的动力性能和...

关键字: 电动汽车 新能源 驱动电源

在现代城市建设中,街道及停车场照明作为基础设施的重要组成部分,其质量和效率直接关系到城市的公共安全、居民生活质量和能源利用效率。随着科技的进步,高亮度白光发光二极管(LED)因其独特的优势逐渐取代传统光源,成为大功率区域...

关键字: 发光二极管 驱动电源 LED

LED通用照明设计工程师会遇到许多挑战,如功率密度、功率因数校正(PFC)、空间受限和可靠性等。

关键字: LED 驱动电源 功率因数校正

在LED照明技术日益普及的今天,LED驱动电源的电磁干扰(EMI)问题成为了一个不可忽视的挑战。电磁干扰不仅会影响LED灯具的正常工作,还可能对周围电子设备造成不利影响,甚至引发系统故障。因此,采取有效的硬件措施来解决L...

关键字: LED照明技术 电磁干扰 驱动电源

开关电源具有效率高的特性,而且开关电源的变压器体积比串联稳压型电源的要小得多,电源电路比较整洁,整机重量也有所下降,所以,现在的LED驱动电源

关键字: LED 驱动电源 开关电源

LED驱动电源是把电源供应转换为特定的电压电流以驱动LED发光的电压转换器,通常情况下:LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: LED 隧道灯 驱动电源
关闭