Prim算法和Kruskal算法的Matlab实现
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
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 算法的基本思想是以局部最优化谋求全局的最优化,而且,还涉及到起始结点的问题。
本程序完成的功能是:从图中的任意结点出发,都能够找出最小生成树
实现方案分析:
Prim算法的关键是如何找到连接U和V-U的最短边来扩充生成树T。设当前T中有k 个点(即T的顶点集U中有k个顶点)则所有满足u U,v V-U的边最多有k条,从如此大的边集中选取最短边是不太经济的。利用MST性质,可以用下述方法构造候选最小边集:对应V-U中的每个顶点,保留从该顶点到U中的各顶点的最短边,取候选边最短边集为V-U中的n-k个顶点所关联的n-k条最短边的集合。为表示候选最短边集,需设置两个一维数组lowcost[n]和adjvex[n],其中lowcost用来保存集合V-U中的各顶点与集合U中顶点的最短边的权值,lowcost[v]=0表示顶点v已经加入最小生成树中;adjvex用来保存依附于该边在集合U中的顶点。例如下式表明顶点和顶点之间的权值为w lowcost[i]=w;
adjvex[i]=k;
程序流程图
关键代码说明:
1.将用于验证算法正确性的两幅图用邻接矩阵的形式保存,分别保存为文件Graph1.m,Graph2.m(注:矩阵的对角线元素设置为零。)并在主程序finallyprim
中直接进行调用。
2.在输入起点时应该给程序的阅读者就该图的顶点数作出提示,不然的话使用者很可能会输入越界下标。采取的方法如下
len=length(graph_adjacent);%求图中有多少个顶点
k=sprintf('please input the point where you want to start ,do remember it must be
between 1 and %d ',len);
start_point=input(k);%输入最小生成树产生起点
采取了sprintf格式化字符串的方法,就避免了编程的人每次根据输入图的顶点
数手动对提示作修改。效果如下:
在对第一幅图进行算法验证时在workspace会如下输出:
please input the point where you want to start ,do remember it must be between 1
and 7
在对第二幅图进行算法验证时在workspace会有如下输出:
please input the point where you want to start ,do remember it must be between 1
and 8
3.在输出结果时为了使结果在workspace中输出的清晰,使人一目了然,也使用了sprintf格式化字符串的方法,代码如下
s=0;
for ii=1:len-1
k=sprintf('最小生成树第%d条边:(%d,%d),权值为%d',ii,tree(ii,1),tree(ii,2),graph_adjacent(tree(ii,1),tree(ii,2)));
disp(k);
disp(' ');
s=s+graph_adjacent(tree(ii,1),tree(ii,2));
end
disp('最小生成树的总代价为:')
disp(s);
4.下面对算法的核心部分进行说明:
在len-1次循环中,每次循环要完成以下三项工作
1.找到最小边,(需要求lowcost数组的最小非零值,因为0表示该边已经被加
入到了最小生成树中)
由于是求非零的最小值,就不能在直接用min函数了。我采取的方法是这
样的:
k=lowcost>0;%k为一逻辑数组,它和lowcost同维,对于每一个位
% 置i如果lowcost(i)>0则k(i)=1
%否则k(i)=0;稍候将用这个数组进行辅助寻址
cost_min=min(lowcost(k));%找出lowcost中除0外的最小值
index=find(lowcost==cost_min);%找出此最小值在lowcost中的下标,
即找到相应的节点
index=index(1);%因为最小值的下标可能不止一个,这里取第一
个下标进行处理