并查集——最小连接路径和Kruskal(hdu1301)
来源:互联网 发布:cms 视频 编辑:程序博客网 时间:2024/05/18 15:56
*没听说过并查集的同学先移步看一下上篇博客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_Findint 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)
- hdu1301 kruskal+并查集
- HDU1301 并查集和最小生成树
- 图 之 MST(最小生成树 — kruskal算法 )并查集实现
- Kruskal算法并查集和最小堆实现
- 算法训练 安慰奶牛 (并查集—路径压缩、Kruskal算法)
- POJ 2485 : 最小生成树(kruskal+并查集)
- 最小生成树(kruskal+并查集实现)
- 最小生成树实现(kruskal+并查集)续
- poj1861最小生成树(并查集)-kruskal算法
- 最小生成树kruskal算法(并查集)
- 最小生成树kruskal算法(并查集)
- HDU 5253 最小生成树(kruskal)+ 并查集
- 最小生成树(Kruskal + 查并集)
- 最小生成树---kruskal模板(并查集优化)
- hdoj 1863 最小生成树(kruskal + 并查集)
- 最小生成树+并查集+ kruskal
- hdu1301 prim和kruskal求最小生成树
- C++11学习笔记
- 单链表结点类型
- OpenGL纹理贴图 JPEG纹理
- 正则表达式
- Oracle 数据库事务隔离级别概述
- 并查集——最小连接路径和Kruskal(hdu1301)
- HDU2594
- 单片机MSP430 - Timer_A 定时器中断程序
- ggedit – interactive ggplot aesthetic and theme editor
- Java开发UUID (全球唯一标识符)截取横线
- jxls使用模板生成excel文件
- php的socket通信
- mac上安装wget的简单方法
- j8583中IsoType类型详解