搜档网
当前位置:搜档网 › Prim算法和Kruskal算法

Prim算法和Kruskal算法

Prim算法和Kruskal算法
Prim算法和Kruskal算法

Prim算法和Kruskal算法

Prim算法和Kruskal算法都能从连通图找出最小生成树。区别在于Prim算法是挨个找,而Kruskal是先排序再找。

一、Prim算法:

Prim算法实现的是找出一个有权重连通图中的最小生成树,即:具有最小权重且连接到所有结点的树。(强调的是树,树是没有回路的)。

Prim算法是这样来做的:

首先以一个结点作为最小生成树的初始结点,然后以迭代的方式找出与最小生成树中各结点权重最小边,并加入到最小生成树中。加入之后如果产生回路则跳过这条边,选择下一个结点。当所有结点都加入到最小生成树中之后,就找出了连通图中的最小生成树了。

Prim算法最小生成树查找过程:

注意:

若候选轻边集中的轻边不止一条,可任选其中的一条扩充到T中。

连通网的最小生成树不一定是惟一的,但它们的权相等。

【例】在上图(e)中,若选取的轻边是(2,4)而不是(2,1)时,则得到如图(h)所示的另一棵

MST。

算法特点

该算法的特点是当前形成的集合T始终是一棵树。将T中U和TE分别看作红点和红边集,V-U看作蓝点集。算法的每一步均是在连接红、蓝点集的紫边中选择一条轻边扩充进T中。MST性质保证了此边是安全的。T从任意的根r开始,并逐渐生长直至U=V,即T 包含了C中所有的顶点为止。MST性质确保此时的T是G的一棵MST。因为每次添加的边是使树中的权尽可能小,因此这是一种"贪心"的策略。

算法分析

该算法的时间复杂度为O(n2)。与图中边数无关,该算法适合于稠密图。

算法演示:

https://www.sodocs.net/doc/a317584484.html,/sjjg/DataStructure/DS/web/flashhtml/prim.htm

二、Kruskal算法:

Kruskal算法与Prim算法的不同之处在于,Kruskal在找最小生成树结点之前,需要对所有权重边做从小到大排序。将排序好的权重边依次加入到最小生成树中,如果加入时产生回路就跳过这条边,加入下一条边。当所有结点都加入到最小生成树中之后,就找出了最小生成树。

算法描述:克鲁斯卡尔算法需要对图的边进行访问,所以克鲁斯卡尔算法的时间复杂度只和边又关系,可以证明其时间复杂度为O(eloge)。

算法过程:

1.将图各边按照权值进行排序

2.将图遍历一次,找出权值最小的边,(条件:此次找出的边不能和已加入最小生成树集合的边构成环),若符合条件,则加入最小生成树的集合中。不符合条件则继续遍历图,寻找下一个最小权值的边。

3.递归重复步骤1,直到找出n-1条边为止(设图有n个结点,则最小生成树的边数应为n-1条),算法结束。得到的就是此图的最小生成树。

克鲁斯卡尔(Kruskal)算法因为只与边相关,则适合求稀疏图的最小生成树。而prime算法因为只与顶点有关,所以适合求稠密图的最小生成树。

无疑,Kruskal算法在效率上要比Prim算法快,因为Kruskal只需要对权重边做一次排序,而Prim算法则需要做多次排序。尽管Prim算法每次做的算法涉及的权重边不一定会涵盖

连通图中的所有边,但是随着所使用的排序算法的效率的提高,Kruskal算法和Prim算法之间的差异将会清晰的显性出来。

Kruskal算法求最小生成树

荆楚理工学院 课程设计成果 学院:_______计算机工程学院__________ 班级: 14计算机科学与技术一班 学生姓名: 志杰学号: 2014407020137 设计地点(单位)_____B5101_________ ____________ 设计题目:克鲁斯卡尔算法求最小生成树__________________________________ 完成日期:2015年1月6日 指导教师评语: ______________ _________________________ ___________________________________________________________________________________ ___________________________________________________________________________________________ ___________________________ __________ _ 成绩(五级记分制):_____ _ __________ 教师签名:__________ _______________

注:介于A和C之间为B级,低于C为D级和E级。按各项指标打分后,总分在90~100为优,80~89为良,70~79为中,60~69为及格,60分以下为不及格。

目录 1 需求分析 (1) 1.1系统目标 (1) 1.2主体功能 (1) 1.3开发环境 (1) 2 概要设计 (1) 2.1功能模块划分 (1) 2.2 系统流程图 (2) 3 详细设计 (3) 3.1 数据结构 (3) 3.2 模块设计 (3) 4测试 (3) 4.1 测试数据 (3) 4.2测试分析 (4) 5总结与体会 (6) 5.1总结: (6) 5.2体会: (6) 参考文献 (7) 附录全部代码 (8)

kruskal算法求最小生成树

#include #include #include #include using namespace std; #define maxn 110 //最多点个数 int n, m; //点个数,边数 int parent[maxn]; //父亲节点,当值为-1时表示根节点 int ans; //存放最小生成树权值 struct eage //边的结构体,u、v为两端点,w为边权值

{ int u, v, w; }EG[5010]; bool cmp(eage a, eage b) //排序调用 { return a.w < b.w; } int Find(int x) //寻找根节点,判断是否在同一棵树中的依据 { if(parent[x] == -1) return x; return Find(parent[x]); } void Kruskal() //Kruskal算法,parent能够还原一棵生成树,或者森林{ memset(parent, -1, sizeof(parent)); sort(EG+1, EG+m+1, cmp); //按权值将边从小到大排序 ans = 0; for(int i = 1; i <= m; i++) //按权值从小到大选择边 { int t1 = Find(EG[i].u), t2 = Find(EG[i].v); if(t1 != t2) //若不在同一棵树种则选择该边,合并两棵树 { ans += EG[i].w; parent[t1] = t2; printf("最小生成树加入的边为:%d %d\n",EG[i].u,EG[i].v); } } } int main() { printf("输入顶点数和边数:"); while(~scanf("%d%d", &n,&m)) { for(int i = 1; i <= m; i++) scanf("%d%d%d", &EG[i].u, &EG[i].v, &EG[i].w); Kruskal(); printf("最小生成树权值之和为:%d\n", ans); } return 0; }

用Prim算法构造最小生成树

用Prim算法构造最小生成树 班级:2010级计算机1班学号:2010131116 姓名:杨才一、实验目的 了解最小生成树的概念,掌握生成最小生成树的方法。 二、实验内容 建立一个含任意结点的无向连通网,并用Prim算法构造其最小生成树 三、实验要点及说明 如果无向连通图是一个网,则其所有生成树中必有一棵树的边的权值总和最小,这棵生成树为最小生成树。 Prim算法:在图G=(V,E)(V为顶点集,E为边集)中任选一顶点v0,令集合U={v0}为初态,在一个顶点在U中,另一顶点在V-U 中的所有边中找权值最小的边(u,v)(U∈ u,v∈ V-U),并将v加入到U中,同时将边(u,v)加入集合T中(T的初态为空集),这样不断地扩大U,直至U=V,则集合T中的边为所求最小生成树的边 四、算法思想与算法描述 1、邻接矩阵的数据类型的定义如下: typedef struct { int no; /*顶点编号*/ string name; /*顶点其他信息*/ } VertexType; /*顶点类型*/ typedef struct/*图的定义*/ { int edges[MAXV][MAXV]; /*邻接矩阵*/ int vexnum,arcnum; /*顶点数,弧数*/ VertexType vexs[MAXV]; /*存放顶点信息*/ }MGraph; 2、临时数组的存放的数据类型 struct { int closest; // U集中的顶点序号 int lowcost; // 边的权值 } closedge[MAXV]; int const INF=32767; /*INF表示∞*/ 3、prime算法实现:(原理见实验说明) void prime(MGraph g,int v) { int lowcost[MAXV]; int min; int closest[MAXV]; int i,j,k; for(i=0;i

最短路径流程图及算法详解

:算法的设计思想 本算法采用分支定界算法实现。构造解空间树为:第一个城市为根结点,与第一个城市相邻的城市为根节点的第一层子节点,依此类推;每个父节点的子节点均是和它相邻的城市;并且从第一个根节点到当前节点的路径上不能出现重复的城市。 本算法将具有最佳路线下界的节点作为最有希望的节点来展开解空间树,用优先队列实现。算法的流程如下:从第一个城市出发,找出和它相邻的所有城市,计算它们的路线下界和费用,若路线下界或费用不满足要求,将该节点代表的子树剪去,否则将它们保存到优先队列中,并选择具有最短路线下界的节点作为最有希望的节点,并保证路径上没有回路。当找到一个可行解时,就和以前的可行解比较,选择一个较小的解作为当前的较优解,当优先队列为空时,当前的较优解就是最优解。算法中首先用Dijkstra算法算出所有点到代表乙城市的点的最短距离。算法采用的下界一个是关于路径长度的下界,它的值为从甲城市到当前城市的路线的长度与用Dijkstra算法算出的当前城市到乙城市的最短路线长度的和;另一个是总耗费要小于1500。 伪代码 算法AlgBB() 读文件m1和m2中的数据到矩阵length和cost中 Dijkstra(length) Dijkstra(cost) while true do for i←1 to 50 do //选择和node节点相邻的城市节点 if shortestlength>optimal or mincost>1500 pruning else if i=50 optimal=min(optimal,tmpopt)//选当前可行解和最优解的 较小值做最优解 else if looped //如果出现回路 pruning //剪枝 else 将城市i插入到优先队列中 end for while true do if 优先队列为空 输出结果 else 取优先队列中的最小节点 if 这个最小节点node的路径下界大于当前的较优解 continue

Kruskal算法说明及图解

1.无向网图及边集数组存储示意图 vertex[6]= 2.Kruskal 方法构造最小生成树的过程 (a)一个图 (b)最小生成树过程1 V0 V1 V2 V3 V4 V5 下标 0 1 2 3 4 5 6 7 8 from 1 2 0 2 3 4 0 3 0 to 4 3 5 5 5 5 1 4 2 weight 12 17 19 25 25 26 34 38 46 V1 V0 V4 V5 V2 V3 V1 V0 V5 V2 V3 V4

(c)最小生成树过程2 (d)最小生成树过程3 (e)最小生成树过程4 3.伪代码 1)初始化辅助数组parent[vertexNum];num=0; 2) 依次考查每一条边for(i=0; i

Prim最小生成树算法实验报告材料

算法分析与设计之Prim 学院:软件学院学号:201421031059 :吕吕 一、问题描述 1.Prim的定义 Prim算法是贪心算法的一个实例,用于找出一个有权重连通图中的最小生成树,即:具有最小权重且连接到所有结点的树。(强调的是树,树是没有回路的)。 2.实验目的 选择一门编程语言,根据Prim算法实现最小生成树,并打印最小生成树权值。 二、算法分析与设计 1.Prim算法的实现过程 基本思想:假设G=(V,E)是连通的,TE是G上最小生成树中边的集合。算法从U ={u0}(u0∈V)、TE={}开始。重复执行下列操作: 在所有u∈U,v∈V-U的边(u,v)∈E中找一条权值最小的边(u0,v0)并入集合TE中,同时v0并入U,直到V=U为止。 此时,TE中必有n-1条边,T=(V,TE)为G的最小生成树。 Prim算法的核心:始终保持TE中的边集构成一棵生成树。 2.时间复杂度 Prim算法适合稠密图,其时间复杂度为O(n^2),其时间复杂度与边得数目无关,N 为顶点数,而看ruskal算法的时间复杂度为O(eloge)跟边的数目有关,适合稀疏图。 三、数据结构的设计 图采用类存储,定义如下: class Graph { private: int *VerticesList; int **Edge; int numVertices; int numEdges; int maxVertices; public: Graph(); ~Graph(); bool insertVertex(const int vertex); bool insertEdge(int v1,int v2,int cost); int getVertexPos(int vertex); int getValue(int i); int getWeight(int v1,int v2); int NumberOfVertices();

svdd算法详解

4.3.3实现技术 (1)KKT 条件,工作集选取及停止准则 在求最小包围球的过程中,迭代没有结束前,每轮迭代会有一个新点被选中,核集中加入新的点后,在核集中的点是下面三种情况之一: 1.核向量,满足KKT 条件; 2.处在球内的非核向量,对应的i α为0,也满足KKT 条件; 3.在(,)t t B c R 外面。刚加入进来的点0l α=违反KKT 条件。 加入新的训练点后,参照传统SVM 方法对核集中的样本点检查是否违反KKT 条件的算法推导如下: 原始问题的KKT 条件: 2 2 (||()||)0i i i R c x αξ?+--= (4.16) 加上已知条件 0i i βξ=,0i i C αβ--= 根据i α的不同,有三种情况: ● 0i α=,有22||()||0i i R c x ξ?+--≥,又i C β=,则0i ξ=,因此有 2 2 ||()||i c x R ?-≤ (4.17) ● 0i C α<<,有22||()||0i i R c x ξ?+--=,又0i β>,则0i ξ=,因此有 2 2 ||()||i c x R ?-= (4.18) ● i C α=,有22||()||0i i R c x ξ?+--=,又0i β=,则0i ξ≥,因此有 2 2 ||()||i c x R ?-≥ (4.19) 每次迭代以对KKT 条件破坏最多的两个样本为工作集,因此,选取以下两个样本下标 2 arg m ax(||()|||) i i s c x C ?α=-< 2 arg m in(||()|||0)i i t c x ?α=-> 若记 2 ||()|| s i g c x ?=-,2||()||t i g c x ?=-

最小生成树的Kruskal算法实现

#include #include #define M 20 #define MAX 20 typedef struct { int begin; int end; int weight; }edge; typedef struct { int adj; int weight; }AdjMatrix[MAX][MAX]; typedef struct { AdjMatrix arc; int vexnum, arcnum; }MGraph; void CreatGraph(MGraph *);//函数申明 void sort(edge* ,MGraph *); void MiniSpanTree(MGraph *); int Find(int *, int ); void Swapn(edge *, int, int); void CreatGraph(MGraph *G)//构件图 { int i, j,n, m; printf("请输入边数和顶点数:\n"); scanf("%d %d",&G->arcnum,&G->vexnum); for (i = 1; i <= G->vexnum; i++)//初始化图{ for ( j = 1; j <= G->vexnum; j++) { G->arc[i][j].adj = G->arc[j][i].adj = 0; } } for ( i = 1; i <= G->arcnum; i++)//输入边和权值

{ printf("请输入有边的2个顶点\n"); scanf("%d %d",&n,&m); while(n < 0 || n > G->vexnum || m < 0 || n > G->vexnum) { printf("输入的数字不符合要求请重新输入:\n"); scanf("%d%d",&n,&m); } G->arc[n][m].adj = G->arc[m][n].adj = 1; getchar(); printf("请输入%d与%d之间的权值:\n", n, m); scanf("%d",&G->arc[n][m].weight); } printf("邻接矩阵为:\n"); for ( i = 1; i <= G->vexnum; i++) { for ( j = 1; j <= G->vexnum; j++) { printf("%d ",G->arc[i][j].adj); } printf("\n"); } } void sort(edge edges[],MGraph *G)//对权值进行排序{ int i, j; for ( i = 1; i < G->arcnum; i++) { for ( j = i + 1; j <= G->arcnum; j++) { if (edges[i].weight > edges[j].weight) { Swapn(edges, i, j); } } } printf("权排序之后的为:\n"); for (i = 1; i < G->arcnum; i++) {

莫队算法详解

莫队算法详解 本文翻译自MO’s Algorithm (Query square root decomposition),作者anudeep2011,发表日期为2014-12-28。由于最近碰到一些莫队算法的题目,找到的相关中文资料都比较简略,而这篇英语文章则讲解的比较详细,故翻译成中文与大家分享。由于本人水平有限,错误在所难免,请谅解。下面是译文。 我又发现了一个有用,有趣但网上资源非常少的话题。在写作之前,我做了一个小调查,令我惊讶的是,几乎所有的印度程序员都不知道该算法。学习这个很重要,事实上所有的codeforces 红名程序员都使用这个算法,比如在div 1 C 题和D 题中。在一年半以前没有这方面的题目,但从那时起这类题目的数量就爆发了!我们可以期待这在未来的比赛中会有更多的这类题目。 莫队算法详解 问题描述 复杂度的简单的解法 一个解决上述问题的算法及其正确性对上述算法的复杂性证明 - 上述算法的适用范围 习题和示例代码 问题描述 给定一个大小为N 的数组,数组中所有元素的大小<=N 。你需要回答M 个查询。每个查询的形式是L ,R 。你需要回答在范围[ L ,R ]中至少重复3次的数字的个数。 例如:数组为{ 1,2,3,1,1,2,1,2,3,1 }(索引从0开始) 查询:L = 0,R = 4。答案= 1。在范围[L ,R]中的值 = { 1,2,3,1,1 },只有1是至少重复3次的。 查询:L = 1, R = 8。答案= 2。在范围[L ,R]中的值 = { 2,3,1,1,2,1,2,3 }, 1重复3遍并且2重复3次。至少重复3次的元素数目=答案= 2。 复杂度的简单的解法 对于每一个查询,从L 至R 循环,统计元素出现频率,报告答案。考虑M = N 的情况,以下程序在最 O ()N 2O (?N ) N ??√O ()N 2 2

分别利用prim算法和kruskal算法实现求图的最小生成树

/*分别利用prim算法和kruskal算法实现求图的最小生成树*/ #include #include #define MaxVertexNum 12 #define MaxEdgeNum 20 #define MaxValue 1000 typedef int Vertextype; typedef int adjmatrix[MaxVertexNum][MaxVertexNum]; typedef Vertextype vexlist[MaxVertexNum]; int visited[MaxVertexNum]={0}; struct edgeElem {int fromvex; int endvex; int weight; }; typedef struct edgeElem edgeset[MaxVertexNum]; void Creat_adjmatrix(vexlist GV,adjmatrix GA,int n,int e) {int i,j,k,w; printf("输入%d个顶点数据",n); for(i=0;i

if(i==j) GA[i][j]=0; else GA[i][j]=MaxValue; printf("输入%d条无向带权边",e); for(k=0;k

PRIM算法求最小生成树

xx学院 《数据结构与算法》课程设计 报告书 课程设计题目 PRIM算法求最小生成树 院系名称计算机科学与技术系 专业(班级) 姓名(学号) 指导教师 完成时间

一、问题分析和任务定义 在该部分中主要包括两个方面:问题分析和任务定义; 1 问题分析 本次课程设计是通过PRIM(普里姆)算法,实现通过任意给定网和起点,将该网所对应的所有生成树求解出来。 在实现该本设计功能之前,必须弄清以下三个问题: 1.1 关于图、网的一些基本概念 1.1.1 图图G由两个集合V和E组成,记为G=(V,E),其中V是顶点的有穷非空集合,E是V中顶点偶对的有穷集,这些顶点偶对称为边。通常,V(G)和E(G)分别表示图G的顶点集合和边集合。E(G)也可以为空集。则图G只有顶点而没有边。1.1.2 无向图对于一个图G,若边集E(G)为无向边的集合,则称该图为无向图。1.1.3 子图设有两个图G=(V,E)G’=(V’,),若V’是V的子集,即V’?V ,且E’是E的子集,即E’?E,称G’是G的子图。 1.1.4 连通图若图G中任意两个顶点都连通,则称G为连通图。 1.1.5 权和网在一个图中,每条边可以标上具有某种含义的数值,该数值称为该边的权。把边上带权的图称为网。如图1所示。 1.2 理解生成树和最小生成树之间的区别和联系 1.2.1 生成树在一个连通图G中,如果取它的全部顶点和一部分边构成一个子图G’,即:V(G’)= V(G)和E(G’)?E(G),若边集E(G’)中的边既将图中的所有顶点连通又不形成回路,则称子图G’是原图G的一棵生成树。 1.2.2 最小生成树图的生成树不是唯一的,把具有权最小的生成树称为图G的最小生成树,即生成树中每条边上的权值之和达到最小。如图1所示。 图1.网转化为最小生成树 1.3 理解PRIM(普里姆)算法的基本思想 1.3.1 PRIM算法(普里姆算法)的基本思想假设G =(V,E)是一个具有n个顶点的连通网,T=(U,TE)是G的最小生成树,其中U是T的顶点集,TE是T的边集,U和TE的初值均为空集。算法开始时,首先从V中任取一个顶点(假定取V0),将它并入U中,此时U={V0},然后只要U是V的真子集,就从那些其一个端点已在T中,另一个端点仍在T外的所有边中,找一条最短(即权值最小)边,假定为(i,j),其中V i∈U,V j∈(V-U),并把该边(i,j)和顶点j分别并入T的边集TE和顶点集U,如此进行下去,每次往生成树里并入一个顶点和一条边,直到n-1次后就把所有n个顶点都并入到生成树T的顶点集中,此时U=V,TE中含有n-1条边,T就是最后得到的最小生成树。可以看出,在普利姆算法中,是采用逐步增加U中的顶点,常称为“加点法”。为了实现这个算法在本设计中需要设置一个辅助数组

Kruskal算法

Kruskal 算法构造最小生成树 构造赋权图(,,)G V E W =,其中12{,,,}n V v v v = 为顶点集合,其中i v 表示第i 个顶点,12{,,,,}i E e e e = 为边的集合,()ij n n W w ?=为邻接矩阵,其中 i j i j ij i j v v v v w v v ∈??=?∞??顶点与之间的距离,当(,) E ,与之间没有边时 科茹斯克尔(Kruskal )算法如下: (1)选1e E ∈(E 为边的集合),使得1e 是权重最小的边。 (2)若12,,e i e e …,已选好,则从12{,,e }i E e e -…,中选取1i e +,使得 i )121{,,e }i e e +…,中无圈,且 ii )是1i e +是12{,,e }i E e e -…,中权重最小的边。 (3)直到选得1V e - 为止。(V 是集合V 中元素的个数) 例:已知9个村庄之间的两两距离见表5,要架设通讯线路把9个村庄连接起来,求所需要通讯线的最小长度。 表5 10个村庄的两两距离数据(单位:km ) (,,)G V E W =,其中129{,, ,}V v v v = 为顶点集合,其中i v 表示第i 个村庄,12{,,,,}i E e e e = 为边的集合,99()ij W w ?=为邻接矩阵,其中 i j i j ij i j v v v v w v v ∈??=?∞??村庄与之间的距离,当(,) E ,与之间没有通讯路线时 科茹斯克尔(Kruskal )算法如下: (1)选1e E ∈(E 为边的集合),使得1e 是距离最小的边。

Prim算法说明及图解

1.无向网图及其邻接矩阵存储示意图 0 34 56 999 999 34 arc[ 6][6]= 34 0 58 999 50 999 56 58 0 76 13 30 999 999 76 0 63 48 999 50 13 63 0 999 34 56 999 999 34 0 2.Prim()算法构造最小生成树过程 1).连通网U={南京} cost={(南京,上海)18,(南京,北京)56,(南京,南昌)999,(南京,天津)999,(南京,徐州)34} 2).U={南京,上海} cost={(南京,北京)56,(南京,南昌)999,(上海,天津)50,(南京,徐州)34} 3).U={南京,上海,天津} cost={(天津,北京)13,(天津,南昌)63,(南京,徐州)34} 4).U={南京,上海,天津,北京} cost={(天津,南昌)63,(北京,徐州)30} 5).U={南京,上海,天津,北京,徐州} cost={(徐州,南昌)48} 6).U={南京,上海,天津,北京,徐州,南昌} cost={} 南京 上海 北京 南昌 天津 徐州 76 48 63 13 30 50 58 18 34 56 南京 上海 南昌 天津 徐州 北京

3.Prim算法构造最小生成树过程中参数变化 南京:v0 上海:v1 北京:v2 南昌:v3 天津:v4 徐州:v5 顶点集 数组 shortEdge 南京上海北京南昌天津徐州U 输出 adjvex lowcost 0 0 0 0 0 0 {v0} {v0,v1} 0 1856 999 999 34 adjvex lowcost 0 0 0 0 1 0 {v0,v1} {v1,v4} 0 0 56 999 5034 adjvex lowcost 0 0 4 4 1 0 {v0,v1,v4} {v4,v2} 0 0 1363 0 34 adjvex lowcost 0 0 4 5 1 2 {v0,v1,v4,v2} {v2,v5} 0 0 0 48 0 30 adjvex lowcost 0 0 4 5 1 2 {v0,v1,v4,v2,v5} {v5,v3} 0 0 0 480 0 adjvex lowcost 0 0 4 3 1 2 {v0,v1,v4,v2,v5,v3} 0 0 0 0 0 0 4.程序主要代码 /***********构造函数***********/ //设置的固定的值方便调试 template MGraph::MGraph() { vertexNum=6; arcNum=8; char a[6][5]={"南京","上海","北京","南昌","天津","徐州"}; int b[]={0,1,14,0,2,46,0,5,21,1,4,32,2,3,37,2,5,25,3,5,25,3,4,38}; for(int i=0; i"<

最小生成树(Prim、Kruskal算法)整理版

一、树及生成树的基本概念 树是无向图的特殊情况,即对于一个N个节点的无向图,其中只有N-1条边,且图中任意两点间有且仅有一条路径,即图中不存在环,这样的图称为树,一般记为T。树定义有以下几种表述: (1)、T连通、无圈、有n个结点,连通有n-1条边;(2)、T无回路,但不相邻的两个结点间联以一边,恰得一个圈;(3)、T连通,但去掉任意一边,T就不连通了(即在点集合相同的图中,树是含边数最少的连通图);(4)、T的任意两个结点之间恰有一条初等链。 例如:已知有六个城市,它们之间要架设电话线,要求任 意两个城市均可以互相通话,并且电话线的总长度最短。若用 六个点v1…v6代表这六个城市,在任意两个城市之间架设电话 线,即在相应的两个点之间连一条边。这样,六个城市的一个 电话网就作成一个图。任意两个城市之间均可以通话,这个图 必须是连通图,且这个图必须是无圈的。否则,从圈上任意去 掉一条边,剩下的图仍然是六个城市的一个电话网。图5-6是 一个不含圈的连通图,代表了一个电话线网。 生成树(支撑树) 定义:如果图G’是一棵包含G的所有顶点的树,则称G’是G的一个支撑树或生成树。例如,图5-7b是图5-7a的一个支撑树。 定理:一个图G有生成树的条件是G是连通图。 证明:必要性显然; 充分性:设图G是连通的,若G不含圈,则按照定义,G是一个树,从而G是自身的一个生成树。若G含圈,则任取G的一个圈,从该圈中任意去掉一条边,得到图G的一生成子图G1。若G1不含圈,则G1是G的一个生成树。若G1仍然含圈,则任取G1的一个圈,再从圈中任意去掉一条边,得到图G的一生成子图G2。依此类推,可以得到图G的一个生成子 图G K,且不含圈,从而G K是一个生成树。 寻找连通图生成树的方法: 破圈法:从图中任取一个圈,去掉一条边。再对剩下的图 重复以上步骤,直到不含圈时为止,这样就得到一个生成树。 取一个圈(v1,v2,v3,v1),在一个圈中去掉边e3。在剩下的图 中,再取一个圈(v1,v2,v4,v3,v1),去掉边e4。再从圈(v3,v4,v5,v3) 中去掉边e6。再从圈(v1,v2,v5,v4,v3,v1)中去掉边e7, 这样,剩下的图不含圈,于是得到一个支撑树,如图所示。 避圈法:也称为生长法,从图中某一点开始生长边,逐步扩展成长为一棵树,每步选取与已入树的边不构成圈的那些边。

线 性 规 划 算 法 详 解

Java基础算法详解 查找和排序算法是算法的入门知识,其经典思想可以用于很多算法当中。因为其实现代码较短,应用较常见。所以在面试中经常会问到排序算法及其相关的问题。但万变不离其宗,只要熟悉了思想,灵活运用也不是难事。一般在面试中最常考的是快速排序和归并排序,并且经常有面试官要求现场写出这两种排序的代码。对这两种排序的代码一定要信手拈来才行。还有插入排序、冒泡排序、堆排序、基数排序、桶排序等。 面试官对于这些排序可能会要求比较各自的优劣、各种算法的思想及其使用场景。还有要会分析算法的时间和空间复杂度。通常查找和排序算法的考察是面试的开始,如果这些问题回答不好,估计面试官都没有继续面试下去的兴趣都没了。所以想开个好头就要把常见的排序算法思想及其特点要熟练掌握,有必要时要熟练写出代码。 冒泡排序 冒泡排序是最简单的排序之一了,其大体思想就是通过与相邻元素的比较和交换来把小的数交换到最前面。这个过程类似于水泡向上升一样,因此而得名。举个栗子,对5,3,8,6,4这个无序序列进行冒泡排序。首先从后向前冒泡,4和6比较,把4交换到前面,序列变成5,3,8,4,6。同理4和8交换,变成5,3,4,8,6,3和4无需交换。5和3交换,变成3,5,4,8,6,3.这样一次冒泡就完了,把最小的数3排到最前面了。对剩下的序列依次冒泡就会得到一个有序序列。冒泡

排序的时间复杂度为O(n^2)。 实现代码: *@Description:冒泡排序算法实现 public class BubbleSort { public static void bubbleSort(int[] arr) { if(arr == null || arr.length == 0) for(int i=0; i) { for(int j=arr.length-1; ji; j--) { if(arr[j]arr[j-1]) { swap(arr, j-1, j); public static void swap(int[] arr, int i, int j) { int temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; 抑或简单理解一点的正向排序 public class BubbleSort { public static void bubbleSort(int[] arr) { if(arr == null || arr.length == 0) for(int i=1;iarr.length-1;i++) { for(int j=0; jarr.length-i; j++) { if(arr[j]arr[j+1]) { swap(arr, j+1, j);

实验5 最小生成树算法的设计与实现(报告)

实验5 最小生成树算法的设计与实现 一、实验目的 1、根据算法设计需要, 掌握连通图的灵活表示方法; 2、掌握最小生成树算法,如Prim、Kruskal算法; 3、基本掌握贪心算法的一般设计方法; 4、进一步掌握集合的表示与操作算法的应用。 二、实验内容 1、认真阅读算法设计教材和数据结构教材内容, 熟习连通图的不同表示方法和最小生成树算法; 2、设计Kruskal算法实验程序。 有n个城市可以用(n-1)条路将它们连通,求最小总路程的和。 设计测试问题,修改并调试程序, 输出最小生成树的各条边, 直至正确为止。 三、Kruskal算法的原理方法 边权排序: 1 3 1 4 6 2 3 6 4 1 4 5 2 3 5 3 4 5 2 5 6 1 2 6 3 5 6 5 6 6 1. 初始化时:属于最小生成树的顶点U={}

不属于最小生成树的顶点V={1,2,3,4,5,6} 2. 根据边权排序,选出还没有连接并且权最小的边(1 3 1),属于最小生成树 的顶点U={1,3},不属于最小生成树的顶点V={2,4,5,6}

3. 根据边权排序,选出还没有连接并且权最小的边(4 6 2),属于最小生成树的顶点U={{1,3},{4,6}}(还没有合在一起,有两颗子树),不属于最小生成树的顶点V={2,5} 4. 根据边权排序,选出还没有连接并且权最小的边(3 6 4),属于最小生成树的顶点U={1,3,4,6}(合在一起),不属于最小生成树的顶点V={2,5}

5. 根据边权排序,选出还没有连接并且权最小的边(3 6 4),属于最小生成树的顶点U={1,2,3,4,6},,不属于最小生成树的顶点V={5} 6. 根据边权排序,选出还没有连接并且权最小的边(3 6 4),属于最小生成树的顶点U={1,2,3,4,5,6}此时,最小生成树已完成

Prim算法和Kruskal算法的Matlab实现

Prim 算法和Kruskal 算法的Matlab 实现 连线问题应用举例: 欲铺设连接n 个城市的高速公路,若i 城与j 城之间的高速公路造价为ij C ,试设计一个线路图,使总的造价最低。 连线问题的数学模型就是图论中在连通的赋权图上求权最小的支撑树。试用Matlab 分别实现求最小支撑数的Prim 算法和Krusal 算法(避圈法)。 一.基本要求: (1) 画出程序流程图; (2) 对关键算法、变量和步骤进行解释说明; (3) 用如下两图对所写算法的正确性进行验证。即输入图的信息,输出对应图 的最小支撑树及其权值。 v 1 v 74 5 v 216 19 6 6 11 2183020 51514 9241 67 53 48 44 (4)分析两种算法的实现复杂度。 二.扩展要求: (1)提供对算法效率(复杂度)进行评估的方法,并通过举例验证,与分析得到的算法复杂度结果相对照; (2)从降低内存消耗、减少计算时间的角度,对算法进行优化。 三.实验步骤 I.用Prim 算法求最小生成树 i .算法分析及需求分析,程序设计 prim 算法的基本思想是:设G=(V ,E )是一个无向连通网,令T=(U ,TE )是G 的最小生成树。T 的初始状态为U={v0}(v0 )TE={},然后重复执行下述操作:在所有u U , v V-U 的边中找一条代价最小的边(u ,v )并入集合TE ,同时v 并入U ,直至U=V 为止。 显然,Prim 算法的基本思想是以局部最优化谋求全局的最优化,而且,还涉及到起始结点的问题。 本程序完成的功能是:从图中的任意结点出发,都能够找出最小生成树

Floyd算法详解

求最短路径算法总结 分类:数据结构 标签: floyd算法 it 部分内容参考 All-Pairs 的最短路径问题:所有点对之间的最短路径 Dijkstra算法是求单源最短路径的,那如果求图中所有点对的最短路径的话则有以下两种解法: 解法一: 以图中的每个顶点作为源点,调用Dijkstra算法,时间复杂度为O(n3); 解法二: Floyd(弗洛伊德算法)更简洁,算法复杂度仍为O(n3)。 n 正如大多数教材中所讲到的,求单源点无负边最短路径用Dijkstra,而求所有点最短路径用Floyd。确实,我们将用到Floyd算法,但是,并不是说所有情况下Floyd都是最佳选择。 对于没有学过Floyd的人来说,在掌握了Dijkstra之后遇到All-Pairs最短路径问题的第一反应可能会是:计算所有点的单源点最短路径,不就可以得到所有点的最短路径了吗。简单得描述一下算法就是执行n次Dijkstra算法。 Floyd可以说是Warshall算法的扩展了,三个for循环便可以解决一个复杂的问题,应该说是十分经典的。从它的三层循环可以看出,它的复杂度是n3,除了在第二层for中加点判断可以略微提高效率,几乎没有其他办法再减少它的复杂度。 比较两种算法,不难得出以下的结论:对于稀疏的图,采用n次Dijkstra比较出色,对于茂密的图,可以使用Floyd算法。另外,Floyd可以处理带负边的图。 下面对Floyd算法进行介绍: Floyd算法的基本思想: 可以将问题分解,先找出最短的距离,然后在考虑如何找出对应的行进路线。如何找出最短路径呢,这里还是用到动态规划的知识,对于任何一个城市而言,i到j的最短距离不外乎存在经过i与j之间的k和不经过k两种可能,所以可以令k=1,2,3,...,n(n是城市的数目),在检查d(ij)与d(ik)+d(kj)的值;在此d(ik)与d(kj)分别是目前为止所知道的i到k 与k到j的最短距离,因此d(ik)+d(kj)就是i到j经过k的最短距离。所以,若有d(ij)>d(ik)+d(kj),就表示从i出发经过k再到j的距离要比原来的i到j距离短,自然把i到j的d(ij)重写为d(ik)+d(kj),每当一个k查完了,d(ij)就是目前的i到j的最短距离。重复这一过程,最后当查完所有的k时,d(ij)里面存放的就是i到j之间的最短距离了。 Floyd算法的基本步骤: 定义n×n的方阵序列D-1, D0 , … Dn-1, 初始化:D-1=C D-1[i][j]=边的长度,表示初始的从i到j的最短路径长度,即它是从i到j的中间不经过其他中间点的最短路径。 迭代:设Dk-1已求出,如何得到Dk(0≤k≤n-1)? Dk-1[i][j]表示从i到j的中间点不大于k-1的最短路径p:i…j, 考虑将顶点k加入路径p得到顶点序列q:i…k…j, 若q不是路径,则当前的最短路径仍是上一步结果:Dk[i][j]= Dk-1[i][j]; 否则若q的长度小于p的长度,则用q取代p作为从i到j的最短路径。

Kruskal算法求最小生成树(java)

Kruskal算法求最小生成树(JA V A) 代码: package homework; import java.util.Scanner; import java.util.Arrays; import java.util.ArrayList; class Edge { public int start;//始边 public int end;//终边 public double cost;//权重 } public class MinSpanningTree_Kruskal{ private static int MAX = 100; private ArrayList edge = new ArrayList();//整个图的边 private ArrayList target = new ArrayList();//目标边,最小生成树private int[] parent = new int[MAX];//标志所在的集合 private static double INFINITY = 99999999.99;//定义无穷大 private double mincost = 0.0;//最小成本 private int n;//结点个数 public MinSpanningTree_Kruskal(){} public static void main(String args[]){ MinSpanningTree_Kruskal sp = new MinSpanningTree_Kruskal(); sp.init(); sp.kruskal(); sp.print(); }//初始化 public void init(){ Scanner scan = new Scanner(System.in); int p,q; double w; System.out.println("请输入结点个数:"); n = scan.nextInt(); System.out.println("请输入各条边及权值(每次输入一组数据按回车确认," + "最后输入-1 -1 -1 结束输入过程)"); while(true){ p = scan.nextInt(); q = scan.nextInt(); w = scan.nextDouble();

相关主题