*没听说过并查集的同学先移步看一下上篇博客http://blog.csdn.net/sm9sun/article/details/53256232

好,首先说一下并查集的标准定义:

概述:

在一些有N个元素的集合应用问题中,我们通常是在开始时让每个元素构成一个单元素的集合,然后按一定顺序将属于同一组的元素所在的集合合并,其间要反复查找一个元素在哪个集合中。这一类问题近几年来反复出现在信息学的国际国内赛题中,其特点是看似并不复杂,但数据量极大,若用正常的数据结构来描述的话,往往在空间上过大,计算机无法承受;即使在空间上勉强通过,运行的时间复杂度也极高,根本就不可能在比赛规定的运行时间(1~3秒)内计算出试题需要的结果,只能用并查集来描述。

结构:

并查集是一种树型的数据结构,用于处理一些不相交集合(Disjoint Sets)的合并及查询问题。常常在使用中以森林来表示。
集就是让每个元素构成一个单元素的集合,也就是按一定顺序将属于同一组的元素所在的集合合并。

操作:

初始化
把每个点所在集合初始化为其自身。
通常来说,这个步骤在每次使用该数据结构时只需要执行一次,无论何种实现方式,时间复杂度均为O(N)。
查找
查找元素所在的集合,即根节点。
合并
将两个元素所在的集合合并为一个集合。
通常来说,合并之前,应先判断两个元素是否属于同一集合,这可用上面的“查找”操作实现。

回到上篇博客的题目,畅通工程的边没有权值,所以相对来说,比较简单,如果有权值或者单向图,并查集可以做吗?显然也是可以的。

因为并查集是树形结构,本身其边就是带有指向性。

我们说并查集的主要用途在于连接、查找、合并操作,那么其应用最广的领域即为图的最小生成树问题——

图的最小生成树:如果连通图G的一个子图是一棵包含G的所有顶点的树,则该子图称为G的生成树。生成树是连通图的包含图中的所有顶点的极小连通子图。(图的生成树不惟一。从不同的顶点出发进行遍历,可以得到不同的生成树)而权值最小的树就是最小生成树。

我们比较熟悉的最小生成树算法是prim算法,其思路是把每两个点的连接状态全部存储下来,即一个二维的邻接矩阵。然后通过贪心的方法进行连接

但如果其点非常多,NxN的邻接矩阵可能会扛不住,而未必每两个点的连接情况都有价值。比如说大部分两个点都没有连接关系。

那么这种情况,我们就适合用于以边计算的Kruskal算法。

Kruskal算法就是在剩下的所有未选取的边中,找最小边,如果和已选取的边构成连接,则放弃,选取次小边。那么连接操作、判断是否已经构成连接,就是运用的

并查集的算法思想。我们看一道例题:

题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=1301

题目描述:

给定村庄数n,用字母表的前n个字母表示,接下来n-1行每行一个村庄字母和与其连接的村庄数以及各村庄的字母和距离。求最小生成树。

解题思路:

用Kruskal算法解决此题,先将所有的边进行排序,依次选取最小的边进行连接,如果该边的2个点已经连接,则遍历次小的边

首先我们构造边的结构体:

struct Side
{
int V_nPoint_a;         //a点
int V_nPoint_b;         //b点
int V_Value_By_ab;//连接ab的边权值
}V_SideMap[5050];

并查集:

int find(int x)                  //查找根
{
    if(P_nNextPoint[x]!=x)
        P_nNextPoint[x]=find(P_nNextPoint[x]);
    return P_nNextPoint[x];
}

int Union(int a,int b)           //合并
{
    int x,y;
    x=find(a);
    y=find(b);
    if(x==y) return 1;
    else 
    {
        P_nNextPoint[y]=x;
        return 0;
    }
}

完整代码:

#include<stdio.h>
#include<string.h>int Get_PointId_by_PointName(char c)
{return int(c-64);
}struct Side
{int V_nPoint_a;int V_nPoint_b;int V_Value_By_ab;
}V_SideMap[5050];int C_nSideCount;void Sort_By_Side(int l,int r)
{if(l>=r)return;Side t;int j=r;int i=l;int si=(l+r)/2;while(i<j){for(;j>si;j--)if(V_SideMap[j].V_Value_By_ab<V_SideMap[si].V_Value_By_ab){      t=V_SideMap[j];V_SideMap[j]=V_SideMap[si];V_SideMap[si]=t;si=j;break;       }for(;i<si;i++)if(V_SideMap[i].V_Value_By_ab>V_SideMap[si].V_Value_By_ab){             t=V_SideMap[i];V_SideMap[i]=V_SideMap[si];V_SideMap[si]=t;si=i;     break;      }}Sort_By_Side(l,i-1);Sort_By_Side(j+1,r);
}//Union_Find
int P_nNextPoint[30];int find(int x)
{if(P_nNextPoint[x]!=x)P_nNextPoint[x]=find(P_nNextPoint[x]);return P_nNextPoint[x];
}int Union(int a,int b)
{int x,y;x=find(a);y=find(b);if(x==y) return 1;else {P_nNextPoint[y]=x;return 0;}
}int main()
{char N_cStPoint,N_cEnPoint_temp;
int C_nListSum;
int V_nSide_temp;
int Point_St_id,Point_En_id;
int n;
int V_nMinAns;
while(scanf("%d",&n)!=EOF&&n)
{getchar();C_nSideCount=1;V_nMinAns=0;
for(int i=1;i<n;i++)
{scanf("%c", &N_cStPoint);scanf("%d", &C_nListSum);while(C_nListSum--){getchar();scanf("%c", &N_cEnPoint_temp);scanf("%d", &V_nSide_temp);Point_St_id=Get_PointId_by_PointName(N_cStPoint);Point_En_id=Get_PointId_by_PointName(N_cEnPoint_temp);V_SideMap[C_nSideCount].V_nPoint_a=Point_St_id;V_SideMap[C_nSideCount].V_nPoint_b=Point_En_id;V_SideMap[C_nSideCount].V_Value_By_ab=V_nSide_temp;C_nSideCount++;}getchar();
}for(int i=1;i<=n;i++)
P_nNextPoint[i]=i;Sort_By_Side(1,C_nSideCount-1);for(int i=1;i<C_nSideCount;i++)
if(!Union(V_SideMap[i].V_nPoint_a,V_SideMap[i].V_nPoint_b))
V_nMinAns+=V_SideMap[i].V_Value_By_ab;printf("%d\n",V_nMinAns);
}
return 0;
}

注:此题n取值范围并不答,更适用于prim算法,只是为了说明并查集应用Kruskal算法。后续会有针对于本题的prim题解~

并查集——最小连接路径和Kruskal(hdu1301)相关推荐

  1. prim——最小连接路径和(hdu1301)

    *本题的Kruskal解法http://blog.csdn.net/sm9sun/article/details/53257264 题目链接: http://acm.hdu.edu.cn/showpr ...

  2. 并查集(压缩路径+按秩排序)

    细节 并查集 可进行合并与查找操作,一个集合可以以其中的一个元素为代表 查找: 两元素代表是否相同(路径压缩优化) 按秩合并:秩就是树的高度,合并时,总是将高度小的树的树根指向高度大的树根,防止 树越 ...

  3. POJ1417 True Liars ——种类并查集+01背包+路径** 好题

    ​​​​​​POJ1417 题意: 有n行输入形如x, y, str,str为yes表示x说y是天使,str为no表示x说y不是天使(x, y为天使,恶魔的编号,1<=x,y<=p+q): ...

  4. 【模板】并查集 两种路径压缩写法(类模板和函数模板)

    并查集函数模板写法: #include <bits/stdc++.h> using namespace std; typedef long long ll; #define MAX_N 1 ...

  5. 并查集 rank排序+路径压缩

    有两个优化点: rank排序 记录两个合并的根的rank rank低的合并到rank高的上 这个优化目的是避免树的深度增加 路径压缩 parent[p] = parent[parent[p]] 这行代 ...

  6. NOIp 数据结构专题总结 (1):STL、堆、并查集、ST表、Hash表

    系列索引: NOIp 数据结构专题总结 (1) NOIp 数据结构专题总结 (2) STL structure std::vector #include <vector> std::vec ...

  7. CF896E Welcome home,Chtholly/[Ynoi2018]五彩斑斓的世界(并查集+第二分块)

    CF896E Welcome home,Chtholly/[Ynoi2018]五彩斑斓的世界 description solution code description 五彩斑斓的世界 CF896E ...

  8. 动态图连通性(线段树分治+按秩合并并查集)

    在考场上遇到了这个的板子题,,,所以来学习了一下线段树分治 + 带撤销的并查集. 题目大意是这样的:有m个时刻,每个时刻有一个加边or撤销一条边的操作,保证操作合法,没有重边自环,每次操作后输出当前图 ...

  9. 【BZOJ4025】二分图(可撤销并查集+线段树分治)

    题目: BZOJ4025 分析: 定理:一个图是二分图的充要条件是不存在奇环. 先考虑一个弱化的问题:保证所有边出现的时间段不会交叉,只会包含或相离. 还是不会?再考虑一个更弱化的问题:边只会出现不会 ...

最新文章

  1. web服务器-nginx
  2. qhfl-6 购物车
  3. 【PAT甲级 素数判断 进制转换】1015 Reversible Primes (20 分) Java版 4/4通过
  4. red hat linux5 u盘安装,RHEL5安装,Red Hat Enterprise Linux 5安装文档
  5. HBase:分布式列式NoSQL数据库
  6. MYSQL--事务隔离
  7. Vijos 1603 ----迷宫(矩阵乘法,矩阵快速幂)
  8. java preference,Java使用Preference类保存上一次记录的方法
  9. 阿里云 centos mysql 5.6_关于centOS安装配置mysql5.6那点事
  10. Gson反序列化详解
  11. matlab选择语句函数,Matlab基本语句和基本函数
  12. C#反射(Reflection)对类的属性get或set值
  13. JavaWeb网络考试系统
  14. i511260h参数 i5 11260h评测
  15. IDEA GitToolBox插件安装教程
  16. 【实践案例分享】阿里文娱智能营销增益模型 ( Uplift Model ) 技术实践
  17. 全国流通经济杂志全国流通经济杂志社全国流通经济编辑部2022年第25期目录
  18. HTML强制关机,如何强制关机【处置技巧】
  19. 高性能网站建设进阶指南:Web开发者性能优化最佳实践 pdf扫描版
  20. 基于Java毕业设计疫情下的居民管理系统源码+系统+mysql+lw文档+部署软件

热门文章

  1. 【十万个编程篇】写文章与“写项目”的差别
  2. C++:函数指针是个什么玩意儿?
  3. C++:map和pair
  4. java实现语音聊天_java 语音聊天核心代码
  5. gdt描述_GDT(Global Descriptor Table)全局描述符表
  6. mapbox 修改初始位置_一行代码教你如何随心所欲初始化Bert参数(附Pytorch代码详细解读)...
  7. numpy 中对axis参数的理解
  8. js验证固定电话、手机号码(代码大全)
  9. php购物车内物品删除,求助 购物车 用session删除 列表的一条
  10. THINKPHP聊天软件H5实时聊天室自动分配账户全开源商业源码