克鲁斯卡尔算法+并查集

算法要点:Kruskal算法的最难点在于怎样判断加入边(x,y)后是否形成了环。

问题可化为:判断边(x,y)的两个顶点x,y在图(实际是森林)mst中最否已经连通。如果已经连通,加入边将形成环;否则,不形成环。

在kruskal算法中,要用到并查集的合并和查找

并查集:

 1 int getfa(int k)        //找到最祖先
 2 {
 3     if(fa[k]==k)    return k;
 4     fa[k]=getfa(fa[k]);
 5     return fa[k];
 6 }
 7
 8 void merge(int x,int y)       //合并祖先
 9 {
10     int fx=getfa(x);
11     int fy=getfa(y);
12     fa[fx]=fy;
13 }
14
15 bool judge(int x, int y)       //判断是不是一个祖先
16 {
17     int fx=getfa(x);
18     int fy=getfa(y);
19     return fx==fy;
20 }

 kruskal算法核心:

 1 for(int i=1;i<=n;i++)
 2         fa[i]=i;
 3 sort(e+1,e+1+len,mys);
 4 int cal=0;
 5 for(int i=1;i<=len;i++)
 6 {
 7     int v=getfa(e[i].x);
 8     int u=getfa(e[i].y);
 9     if(v!=u)
10     {
11         merge(v,u);
12                 //根据题意添加
13         if(++cal==n-1)
14         {
15             break;
16         }
17     }
18 }

输入:

 1 int fa[maxn];
 2 int len=0;
 3 struct node
 4 {
 5     int x,y,v;
 6 }e[maxn];
 7
 8 void init(int xx,int yy,int vv)
 9 {
10     if(yy<0||yy>n*m)    return;
11     e[++len].y=yy;
12     e[len].x=xx;e[len].v=vv;
13 }
14
15 int main()
16 {
17     memset(e,0,sizeof(e));
18     cin>>n>>m;
19     for(int i=1;i<=m;i++)
20     {
21         int xx,yy,vv;
22         cin>>xx>>yy>>vv;
23         init(xx,yy,vv);
24         init(yy,xx,vv);
25     }
时间: 2024-08-05 19:33:17

克鲁斯卡尔算法+并查集的相关文章

最小生成树算法汇总 (普里姆 &amp;&amp; 克鲁斯卡尔与并查集结合)

最小生成树: 今天研究了一下最小生成树,感觉最小生成树算法与最短路算法 相差不大,从Prim 与 Dijskrs算法可以看出 最小生成树即最小权重生成树,主要适用于 N个点之间 构造N-1线路,使N个点之间任意两点之间都可到达, 但是N个点之间 不构成回路,并且这N-1条线路的权重之和最小即 消耗最小. 注意:在构造最小生成树,加入新的节点时,不仅要保证权重最小,首要条件是 不能构成回路. 以图示为例,构造最小生成树 (一)普里姆   以下步骤 (二) 克鲁斯卡尔 最终的最小生成树 和 普里姆一

hdu 1233(还是畅通工程)(prime算法,克鲁斯卡尔算法)(并查集,最小生成树)

还是畅通工程 Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 26860    Accepted Submission(s): 11985 Problem Description 某省调查乡村交通状况,得到的统计表中列出了任意两村庄间的距离.省政府"畅通工程"的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路

hdu 1233(还是畅通project)(prime算法,克鲁斯卡尔算法)(并查集,最小生成树)

还是畅通project Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 26860    Accepted Submission(s): 11985 Problem Description 某省调查乡村交通状况,得到的统计表中列出了随意两村庄间的距离.省政府"畅通project"的目标是使全省不论什么两个村庄间都能够实现公路交

hdu-1863畅通工程 最小生成树克鲁斯卡尔算法kruskal(并查集实现)

畅通工程 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 16994    Accepted Submission(s): 7134 Problem Description 省政府"畅通工程"的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可).经过调查评估,得到的统计表中列出

hdu5441 并查集+克鲁斯卡尔算法

这题计算 一张图上 能走的 点对有多少个  对于每个限制边权 , 对每条边排序,对每个查询排序 然后边做克鲁斯卡尔算法 的时候变计算就好了 #include <iostream> #include <algorithm> #include <string.h> #include <cstdio> #include <vector> #include <queue> using namespace std; const int maxn

贪心算法(Greedy Algorithm)之最小生成树 克鲁斯卡尔算法(Kruskal&amp;#39;s algorithm)

克鲁斯卡尔算法(Kruskal's algorithm)是两个经典的最小生成树算法的较为简单理解的一个.这里面充分体现了贪心算法的精髓.大致的流程能够用一个图来表示.这里的图的选择借用了Wikipedia上的那个.很清晰且直观. 首先第一步,我们有一张图,有若干点和边 例如以下图所看到的: 第一步我们要做的事情就是将全部的边的长度排序,用排序的结果作为我们选择边的根据.这里再次体现了贪心算法的思想.资源排序,对局部最优的资源进行选择. 排序完毕后,我们领先选择了边AD. 这样我们的图就变成了 第

克鲁斯卡尔算法

环境: Codeblocks 13.12 + GCC 4.7.1 参考资料:<大话数据结构>,<啊哈算法>,百度百科 基本思想:(1)构造一个只含n个顶点,边集为空的子图.若将图中各个顶点看成一棵树的根节点,则它是一个含有n棵树的森林.(2)从网的边集 E 中选取一条权值最小的边,若该条边的两个顶点分属不同的树,则将其加入子图.也就是说,将这两个顶点分别所在的两棵树合成一棵树:反之,若该条边的两个顶点已落在同一棵树上,则不可取,而应该取下一条权值最小的边再试之(3)依次类推,直至森

最小生成树( 克鲁斯卡尔算法)

/* Name: Copyright: Author: Date: 01-12-14 20:17 Description: 最小生成树( 克鲁斯卡尔算法) 关于并查集的算法,参见<一种简单而有趣的数据结构--并查集>http://blog.csdn.net/qiaoruozhuo/article/details/39674991 */ #include<stdio.h> #include<stdlib.h> #define MAXN 1000 //最大顶点数量 #def

最小生成树算法(克鲁斯卡尔算法和普里姆算法)

一般最小生成树算法分成两种算法: 一个是克鲁斯卡尔算法:这个算法的思想是利用贪心的思想,对每条边的权值先排个序,然后每次选取当前最小的边,判断一下这条边的点是否已经被选过了,也就是已经在树内了,一般是用并查集判断两个点是否已经联通了: 另一个算法是普里姆算法:这个算法长的贼像迪杰斯塔拉算法,首先选取一个点进入集合内,然后找这个点连接的点里面权值最小的点,然后每次在选取与集合内任意一点连接的点的边的权值最小的那个(这个操作可以在松弛那里修改一下,这也是和迪杰斯塔拉算法最大的不同,你每次选取一个点后