最小生成树的应用.docx
- 文档编号:30568203
- 上传时间:2023-08-16
- 格式:DOCX
- 页数:21
- 大小:164.61KB
最小生成树的应用.docx
《最小生成树的应用.docx》由会员分享,可在线阅读,更多相关《最小生成树的应用.docx(21页珍藏版)》请在冰豆网上搜索。
最小生成树的应用
武夷学院
课程设计报告
课程名称:
数据结构(C言语版本)
设计题目:
最小生成树的应用
学生班级:
10计科1班
学生姓名:
陈娟,谢贤根,黄伟伟,陈开槟
指导教师:
林丽惠
完成日期:
2012-01-05
课程设计项目研究报告
一、为题描述及基本要求
在n个城市间建立通信网络,需架设n-1条线路。
求解如何以最低经济代价建设此通信网,这是一个最小生成树问题。
要求:
(1)利用普利姆算法求网的最小生成树;
(2)输出生成树中各边及权值。
二、实现本程序需要解决的问题如下
(1)、如何选择存储结构去建立一个带权网络。
(2)、如何在所选存储结构下输出这个带权网络。
(3)、如何实现prim算法的功能。
(4)、如何从每个顶点开始找到所有的最小生成树的顶点。
(5)、如何输出最小生成树的边及其权值。
此问题的关键在于如何实现prim算法,实现的过程中如何得到构成最小生成树的所有顶点,此外输出也是一个关键问题所在,在此过程中经过了多次调试。
首先我们对问题进行大致的概要分析:
这个问题主要牵涉到通过prim的基本算法思想实现程序所要求的功能,该算法的主要思想是:
假设N=(V,{E})是连通网,TE是N上最小生成树中边的集合。
算法从U={u0}(u0∈V),TE={}开始,重复执行下述操作:
在所有u∈U,v∈V-U的边(u,v)∈E中找一条代价最小的边(u0,v0)并入集合TE,同时v0并入U,直至U=V为止。
此时TE中必有n-1条边,则T=(V,{E})为N的最小生成树。
问题的输入数据的格式为:
首先提示输入带权网络的顶点边数,我定义的为整形数据型,然后输入每一条边的信息,即边的两个顶点以及权值,是十进制整数类型,这样我们就建立一个带权网络,并用邻接矩阵来存储,生成一个方阵显示出来。
问题的输出数据格式为:
输出是以邻接矩阵形式输出,以及从不同顶点开始生成的最小生成树。
题目要求以及达到目标:
题目要求用prim算法实现给定无向网中边e和顶点n实现生成的最小生成树,输出生成树中的各边及权值。
三、测试数据
第一组
顶点数(vertices)、边数(edge):
4、5
起始节点(starting)、下个节点(terminal)、权值(weights):
1,2,1
1,3,2
2,4,5
3,4,4
1,4,6
预测结果<1,2>1、<1,3>2、<3,4>4
第二组
顶点数(vertices)、边数(edge):
6,10,
起始节点(starting)、下个节点(terminal)、权值(weights):
1,2,6
1,3,1
1,4,5
2,3,5
2,5,3
3,5,6
3,4,5
3,6,4
4,6,2
5,6,6
预测结果<1,3>1、<3,6>4、<6,4>2、<3,2>5、<2,5>3
四、算法思想
普里姆算法的基本思想:
普里姆算法是另一种构造最小生成树的算法,它是按逐个将顶点连通的方式来构造最小生成树的。
从连通网络N={V,E}中的某一顶点u0出发,选择与它关联的具有最小权值的边(u0,v),将其顶点加入到生成树的顶点集合U中。
以后每一步从一个顶点在U中,而另一个顶点不在U中的各条边中选择权值最小的边(u,v),把该边加入到生成树的边集TE中,把它的顶点加入到集合U中。
如此重复执行,直到网络中的所有顶点都加入到生成树顶点集合U中为止。
假设N=(V,{E})是一个连通网,TE是N上最小生成树中边的集合。
则构造N的最小生成树的步骤如下:
(1)初始状态,TE为{},U={u0},u0∈V;
(2)在所有u∈U,v∈V-U的边(u,v)∈E中找一条代价最小的边(u′,v′)并入TE,同时将v′并入U;
重复执行步骤
(2)n-1次,直到U=V为止。
在普里姆算法中,为了便于在集合U和(V-U)之间选取权值最小的边,需要设置两个辅助数组closest和lowcost,分别用于存放顶点的序号和边的权值。
对于每一个顶点v∈V-U,closest[v]为U中距离v最近的一个邻接点,即边(v,closest[v])是在所有与顶点v相邻、且其另一顶点j∈U的边中具有最小权值的边,其最小权值为lowcost[v],即lowcost[v]=cost[v][closest[v]],采用邻接表作为存储结构:
设置一个辅助数组:
lowcost域 存放生成树顶点集合内顶点到生成树外各顶点的各边上的当前最小权值;
closest域 记录生成树顶点集合外各顶点距离集合内哪个顶点最近(即权值最小)。
用prim算法构造最小生成树的过程:
五、模块划分
(1)预处理
#include
#include
#defineinf9999
#definemax40
#definelinelenght77
(2)建立无向图
intadjg(intg[][max])/*建立无向图*/
{
intn,e,i,j,k,v1=0,v2=0,weight=0;
printf("Inputthenumberofvertices,numberoftheedge:
");
scanf("%d,%d",&n,&e);
while(e<=0||e>0.5*n*(n-1)||n>=max)/*最大边数为
,即0.5*n*(n-1)*/
{
error();
printf("Inputthenumberofvertices,numberoftheedge:
");
scanf("%d,%d",&n,&e);
}
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
g[i][j]=inf;/*初始化矩阵,全部元素设为无穷大*/
for(k=1;k<=e;k++)
{
printf("Inputthe%dontheedgeofthestartingpoint,terminal,weights:
",k);
scanf("%d,%d,%d",&v1,&v2,&weight);
while(v1==v2||v1>n||v2>n||v1<1||v2<1)
{
error();
printf("Inputthe%dontheedgeofthestartingpoint,terminal,weights:
",k);
scanf("%d,%d,%d",&v1,&v2,&weight);
}
g[v1][v2]=weight;/*无向网的邻接矩阵是对称矩阵*/
g[v2][v1]=weight;
}
return(n);
}/*返回顶点个数n*/
(3)输出无向图的邻接矩阵
voidpri(intg[][max],intn)/*输出无向图的邻接矩阵*/
{
inti,j;
for(i=0;i<=n;i++)
printf("%d\t",i);
for(i=1;i<=n;i++)
{
printf("\n%d\t",i);
for(j=1;j<=n;j++)/*输出边的权值*/
{
if(g[i][j]==inf)printf("%c\t",'\354');
elseprintf("%d\t",g[i][j]);
}
}
printf("\n");
}
voidprim(intg[][max],intn)/*prim函数*/
{
intlowcost[max],closest[max];
inti,j,k,min;
for(i=2;i<=n;i++)
{lowcost[i]=g[1][i];/*初始化*/
closest[i]=1;
}
lowcost[1]=0;/*标志顶点1加入U集合*/
for(i=2;i<=n;i++)/*形成n-1条边的生成树*/
{
min=inf;
k=0;
for(j=2;j<=n;j++)/*寻找权值最小的一条边,并把权值赋给min*/
if((lowcost[j] =0)) { min=lowcost[j]; k=j; } printf("(%d,%d)%d\t",closest[k],k,min); lowcost[k]=0;/*顶点k加入U*/ for(j=2;j<=n;j++)/*修改由顶点k到其他顶点边的权值*/ if(g[k][j] { lowcost[j]=g[k][j]; closest[j]=k; } printf("\n"); } } (4)输出一条分割线 intpriline(inth)/*输出一条分割线*/ { intg; printf("\n|"); for(g=0;g printf("*"); printf("|\n"); } (5)提示错误信息 interror()/*提示错误信息*/ { printf("\n\n|************************E*R*R*O*R************************|\n"); printf("InputerrorsorDataoverflowpleasere-enter\n\n"); fflush(stdin);/*清除缓存*/ } (6)主函数 voidmain()/*主函数*/ { intg[max][max],n;priline(linelenght); n=adjg(g);priline(linelenght);priline(linelenght); printf("Inputtheadjacencymatrixwithoutdirectedgraph: \n"); pri(g,n); printf("\n"); printf("Minimumspanningtreestructure: \n"); prim(g,n); getch(); } 六、算法设计与分析 (1)关于带权网络的存储形式 要实现对于任意给定带权网络和顶点,运用PRIM基本算法思想求解所有的最小生成树的运算。 在这里我们首先要明确所选用的数据结构,即选用何种数据结构存储来存储带权网络,这是必选首先解决的问题,所以我们选择了图的邻接矩阵存储方式来存储带权网络,建图时采用邻接矩阵的结构,定义邻接矩阵用到了一维数组和二维数组,分别存储顶点信息和边的权值。 由于该算法对图中的边的权值频繁比较,所以采用邻接矩阵比较方便,并在此基础上实现带权网络的建立以及输出显示。 (2)关于普利姆算法的基本思想 Prim算法求最小生成树的主要思想 此算法是普利姆与1957年提出的一种构造最小生成树的算法,主要思想是: 假设N=(V,{E})是连通网,TE是N上最小生成树中边的集合。 算法从U={u0}(u0∈V),TE={}开始,重复执行下述操作: 在所有u∈U,v∈V-U的边(u,v)∈E中找一条代价最小的边(u0,v0)并入集合TE,同时v0并入U,直至U=V为止。 此时TE中必有n-1条边,则T=(V,{E})为N的最小生成树。 对于最小生成树问题 最小生成树是指在所有生成树中,边上权值之和最小的生成树,另外最小生成树也可能是多个,他们之间的权值之和相等。 (3)概要设计 通过邻接矩阵的建立,可以将任意两点的权值存入其中,便于进行各边的权值的比较修改,在普利姆算法中,为实现这个算法需附设一个辅助数组closedge,以记录从U到V-U具有最小代价的边,对每个顶点vi∈V-U,在辅助数组中存在一个相应分量closedge[i-1],他包括两个域,其中lowcost存储该边上的权值。 显然, closedge[i-1].lowcost=Min{cost(u,vi)|u∈U} 从算法可以看出每加入一个顶点到U中,closedge数组都会发生相应的变化。 程序模块之间的调用: 在主函数中调用邻接矩阵的初始化函数,邻接矩阵的生成函数,PRIM算法的函数,图的构造函数,输出函数。 邻接矩阵的生成函数主要解决的是边的信息存储问题,而PRIM算法的函数是解决计算出最小生成树的功能。 详细设计和编码 首先我在接下来给出总的流程: 结果分析: 本课程设计的要求 对于任意给定的网和起点,用PRIM算法的基本思想求解出所有的最小生成树并输出这些边的权值,所以如何实现输出显示所有的最小生成树关键问题所在,经过分析调试,用一个for语句就可以解决这个问题,从每个顶点出发,开始每一次遍历并输出显示出来。 算法的时间和空间性能分析 根据程序中算法的循环语句可以判断出普利姆算法的时间复杂度为O(n2)算法和图中的边数无关。 因此普利姆算法适合求稠密网的最小生成树,因为在算法中用邻接矩阵的存储结构,在无向图中,邻接矩阵是对称的。 所以仅需要存储上三角或下三角的元素,因此需要n(n+1)的存储空间。 测试结果 界面的截图 输入的情况的截图 输出结果的截图 输入错误的截图 七、源程序 #include #include #defineinf9999 #definemax40 #definelinelenght77 intadjg(intg[][max])/*建立无向图*/ { intn,e,i,j,k,v1=0,v2=0,weight=0; printf("Inputthenumberofvertices,numberoftheedge: "); scanf("%d,%d",&n,&e); while(e<=0||e>0.5*n*(n-1)||n>=max)/*最大边数为 ,即0.5*n*(n-1)*/ { error(); printf("Inputthenumberofvertices,numberoftheedge: "); scanf("%d,%d",&n,&e); } for(i=1;i<=n;i++) for(j=1;j<=n;j++) g[i][j]=inf;/*初始化矩阵,全部元素设为无穷大*/ for(k=1;k<=e;k++) { printf("Inputthe%dontheedgeofthestartingpoint,terminal,weights: ",k); scanf("%d,%d,%d",&v1,&v2,&weight); while(v1==v2||v1>n||v2>n||v1<1||v2<1) { error(); printf("Inputthe%dontheedgeofthestartingpoint,terminal,weights: ",k); scanf("%d,%d,%d",&v1,&v2,&weight); } g[v1][v2]=weight;/*无向网的邻接矩阵是对称矩阵*/ g[v2][v1]=weight; } return(n); }/*返回顶点个数n*/ voidpri(intg[][max],intn)/*输出无向图的邻接矩阵*/ { inti,j; for(i=0;i<=n;i++) printf("%d\t",i); for(i=1;i<=n;i++) { printf("\n%d\t",i); for(j=1;j<=n;j++)/*输出边的权值*/ { if(g[i][j]==inf)printf("%c\t",'\354'); elseprintf("%d\t",g[i][j]); } } printf("\n"); } voidprim(intg[][max],intn)/*prim函数*/ { intlowcost[max],closest[max]; inti,j,k,min; for(i=2;i<=n;i++) {lowcost[i]=g[1][i];/*初始化*/ closest[i]=1; } lowcost[1]=0;/*标志顶点1加入U集合*/ for(i=2;i<=n;i++)/*形成n-1条边的生成树*/ { min=inf; k=0; for(j=2;j<=n;j++)/*寻找权值最小的一条边,并把权值赋给min*/ if((lowcost[j] =0)) { min=lowcost[j]; k=j; } printf("(%d,%d)%d\t",closest[k],k,min); lowcost[k]=0;/*顶点k加入U*/ for(j=2;j<=n;j++)/*修改由顶点k到其他顶点边的权值*/ if(g[k][j] { lowcost[j]=g[k][j]; closest[j]=k; } printf("\n"); } } intpriline(inth)/*输出一条分割线*/ { intg; printf("\n|"); for(g=0;g printf("*"); printf("|\n"); } interror()/*提示错误信息*/ { printf("\n\n|************************E*R*R*O*R************************|\n"); printf("InputerrorsorDataoverflowpleasere-enter\n\n"); fflush(stdin);/*清除缓存*/ } voidmain()/*主函数*/ { intg[max][max],n;priline(linelenght); n=adjg(g);priline(linelenght);priline(linelenght); printf("Inputtheadjacencymatrixwithoutdirectedgraph: \n"); pri(g,n); printf("\n"); printf("Minimumspanningtreestructure: \n"); prim(g,n); getch(); } 八、测试数据 第一组 第二组 九、课程设计项目进度表及任务分配表及任务分配表 进度 日期 进度 2012-1-2 搜集资料 2012-1-2至3 设计算法 2012-1-4 将问题分块,然后分块写出程序 2012-1-5 将每块程序衔接好,进行调试 2012-1-5 对程序进行最后修改,整理实验报告 分配表 成员 座号 项目内容 序号 陈娟 45号 编写程序调试程序 01 谢贤根 12号 收集资料调试程序 02 黄伟伟 5号 收集资料调试程序 03 陈开槟 13号 收集资料word排版 04 十、设计心得 陈娟: 此次的课程设计为: 最小生成树的应用。 主要包括三个部分。 即: 建立无向网,输出邻接矩阵,输出最小生成树(边和权值)。 其中对于实现最小生成树我们用了prim算法。 而prim算法也是此实验的重点和难点。 其过程如下图: 此实验的prim算法用了较多的循环语句。 让我对他们的使用有了更熟练的应用。 黄伟伟: 通过本次实验我学会了通过prime算法生成最小生成树的问题。 所谓生成树,就是n个点之间连成n-1条边的图形。 而最小生成树,就是权值(两点间直线的值)之和的最小值。 首先,要用二维数组记录点和权值,然后再求最小生成树。 具体方法是: 1.先选取一个点作起始点,然后选择它邻近的权值最小的点(如果有多个与其相连的相同最小权值的点,随便选取一个)。 2.再在伸延的点找与它邻近权值最小的点,与前一个已加入生成树的顶点。 3.如此类推,当所有点都连同后,结果最生成树如上图所示。 所有权值相加就是最小生成树。 谢贤根+陈开槟: 在做最小生成树的课程设计中,由于我知识掌握的不好,很多都需要同组队员的帮忙,让我了解到团结的力量。 我们做事情,团结很重要,一个事件的是否顺利成功,往往需要团队中每天团员之间的相互帮助,互相配合。 通过这次的课程设计实验,加强了我对最小生成树的理解,同时也对普利姆算法有了比较深刻的了解,而且,在实验的过程中,加强我的动手能力,虽说不能做的很好,但也有尽力而为了。 本次实验也告诫了我要认真掌握书本的知识,多理解,并且要学会灵活应用书本的知识。 十一、参考文献 参考目录书 (1)求最小生成树,普里姆(Prim)算法-EdwardLewis的日志-网易博客 (2)严蔚敏,吴伟明。 数据结构: c语言版。 清华大学出版社, (3)严蔚敏数据结构与算法,XX视频 学校地址: 福建省武夷山市武夷大道16号 设计单位: 数学与计算机系 版本号: WyuKcsjVer2007
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 最小 生成 应用