基于最小生成树的小区网线铺设问题的实现.docx
- 文档编号:11758566
- 上传时间:2023-03-31
- 格式:DOCX
- 页数:16
- 大小:45.64KB
基于最小生成树的小区网线铺设问题的实现.docx
《基于最小生成树的小区网线铺设问题的实现.docx》由会员分享,可在线阅读,更多相关《基于最小生成树的小区网线铺设问题的实现.docx(16页珍藏版)》请在冰豆网上搜索。
基于最小生成树的小区网线铺设问题的实现
题目:
基于最小生成树的小区网线铺设问题的实现
初始条件:
理论:
学习了《数据结构》课程,掌握了基本的数据结构和常用的算法;
实践:
计算机技术系实验室提供计算机及软件开发环境。
要求完成的主要任务:
(包括课程设计工作量及其技术要求,以及说明书撰写等具体要求)
1、系统应具备的功能:
(1)建立小区网络用户间的最小生成树;
(2)实现小区网线铺设问题;
(3)演示结果。
2、数据结构设计;
3、主要算法设计;
4、编程及上机实现;
5、撰写课程设计报告,包括:
(1)设计题目;
(2)摘要和关键字;
(3)正文,包括引言、需求分析、数据结构设计、算法设计、程序实现及测试、不足之处、设计体会等;
(4)结束语;
(5)参考文献。
时间安排:
2007年7月2日-7日(第18周)
7月2日查阅资料
7月3日系统设计,数据结构设计,算法设计
7月4日-5日编程并上机调试
7月6日撰写报告
7月7日验收程序,提交设计报告书。
指导教师签名:
2007年7月2日
系主任(或责任教师)签名:
2007年7月2日
小区铺设网线
摘要在一个小区中铺设网线,设计一个程序,使其成本最低。
本程序从这个实际问题出发,将其抽象为求最小生成树的问题,并通过C语言实现,输入结点的个数及它们之间的距离,即可求解最优的铺设方案。
程序求解最小生成树时是通过Prim算法实现。
关键词最小生成树Prim算法最短路径无向图
0.引言
《数据结构》是计算机科学与技术、软件工程及相关学科的专业基础课,也是软件设计的技术基础。
《数据结构》课程的教学要求之一是训练学生进行复杂的程序设计的技能和培养良好程序设计的风格,其重要程度决不亚于理论知识的传授,因此课程设计环节是一个至关重要的环节,是训练学生从事工程科技的基本能力,是培养创新意识和创新能力的极为重要的环节。
基本要求如下:
(1)熟练掌握基本的数据结构;
(2)熟练掌握各种算法;
(3)运用高级语言编写质量高、风格好的应用程序。
因此在这个课程设计中我选择的是在一个小区中铺设网线,如何是其成本达到最小。
这个实验的实验要求是使用Prim算法,对给定的连通图求出最小生成树并将之输出。
1.需求分析
在一个小区中铺设网线,如何是其成本达到最小,是一个在现实中非常重要的问题。
这一类的问题在现实中是非常多的,各种线路的架设,道路的修建等,都使它有重要的现实经济意义。
具体到小区铺设网线问题,若要在N间楼房之间铺设网线,只需铺设N-1条线路即可,如何以最低的成本建设这个通信网这个问题的数学描述就是求最小生成树的问题,可以使用Prim算法或者Kruscal算法,两者都是求解最小生成树的典型算法。
本程序是使用Prim算法编成。
在小区内进行网线的铺设,最现实的问题之一就是经济成本的问题。
如何设计网线的铺设路线,使其在经济成本上达到最优化,是需要认真考虑的。
在数学上,这一类的问题就是在一个无向图中求最小生成树的问题。
在算法上已经有很成熟的解决方案。
本程序就是使用的Prim算法,结合实际问题,通过输入结点个数,可以理解为楼房的栋数,以及边的权值,可以理解为楼房之间的距离,求出最小生成树,即最佳的铺设方案。
这样就把一个实际的问题,抽象成了一个数学问题,并使之得到了解决,达到了求出最短路径,经济上最优化的目的。
2.数据结构设计
在本程序中,用2个数组分别储存点集和边集,用一个矩阵储存边的权值,即邻接矩阵,在程序中建立邻接矩阵后通过输入数值使其初始化,其部分代码如下:
intg[max][max],n,e,weight,k,i,j,v1,v2;/*建立无向图*/
printf("inputthenumberofvertexandedge:
");
scanf("%d%d",&n,&e);/*初始化矩阵*/
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
{
if(i==j)
g[i][j]=0;
else
g[i][j]=inf;
}
3.算法设计
求一个连通图的最小生成树,其主要的成熟算法是Prim算法和Kruscal算法,Prim算法是R。
C。
Prim在1957年提出的算法,不过他也并不全是这个算法最早提出者,最早的应该是捷克人V。
Jarník在1930年提出的算法,不过他的文章是用捷克语写的,光看标题就看不明白了。
有人也把这个算法就叫做Prim-Jarnik算法。
Prim算法简单有效,它从图的一个指定的顶点出发,用V表示树顶点集,初始只有那个指定的顶点;E表示最终最小生成树中有的边的集合,初始是空集。
从V中的顶点出发,找到从这个顶点出发的权值最小的边,如果这条边不构成回边,那么选入最小生成树,并将这条边加到E集合中,边的另一端结点加入到V集合中。
这样一直循环到V中的顶点为图的所有顶点为止,最小生成树就存在E集合里面了。
证明这个算法是否正确可以利用归纳法,在从T(i-1)是最小生成树到T(i)是最小生成树的判定过程中使用反证法,就可以证明这样选出来的树一定是最小生成树。
可能这个算法还有它的提升空间,但是不管怎么提升,基础性的想法不会有什么变化,所以不会有什么质的差别。
Kruskal算法是KruskalJ。
B在1956年的论文里面提出来的。
它从边的角度出发,每一次将图中的权值最小的边取出来,在不是回边,也就是说不构成环的情况下,将边加入最小生成树中,重复这个过程,直到所有的图中所有的点都加入到最小生成树中结束。
从空间上讲,显然在Prim算法中,我们只需要很小的空间就可以完成算法,因为每一次我们都是从个别点开始出发进行扫描的,而且每一次扫描也只扫描与当前顶点集对应的边,但在Kruskal算法中,因为我们每时每刻都得知道当前的树里面权值最小的边在哪里,这样我们需要对所有的边进行排序。
对于很大的图来讲,这个需要占用比Prim算法大的多的空间。
其中Prim算法相比于Kruscal算法更适合在稠密的图中求解最小生成树,因为kruskal算法对边的稀疏图比较合适,时间复杂度为o(elog2e),e是边数,与顶点无关。
而Prim算法的时间复杂度为O(n^2),与边无关,适用于边稠密的图,比较符合在小区中铺设网线的实际情况,因为在现实中任意两栋楼房之间一般都是可以用网线连接的。
因此本程序使用了Prim算法。
其过程大致描述为:
3.1设图G=(V,E),其生成树的顶点集合为U。
3.1.1把v0放入U。
3.1.2在所有u∈U,v∈V-U的边(u,v)∈E中找一条最小权值的边,加入生成树。
3.1.3把3.1.2找到的边的v加入U集合。
如果U集合已有n个元素,则结束,否则继续执行3.1.2。
其算法的时间复杂度为O(n^2)
3.2Prim算法实现时的数据存储:
3.2.1集合:
设置一个数组set(i=0,1,。
。
,n-1),初始值为0,代表对应顶点不在集合中(注意:
顶点号与下标号差1)
3.2.2图用邻接阵表示,路径不通用无穷大表示,在计算机中可用一个大整数代替。
本程序中直接输出inf来代替。
3.3以下是算法的伪码描述:
首先定义数据类型:
typeadjmatrix=array[1..n,1..n]ofreal;
//定义一个n*n的矩阵类型adjmatrix,以便存储邻接矩阵//
edge=record
beg,en:
1。
。
n;
length:
real;
end;
//定义边的存储结构为edge,其中beg是边的起点,en是边的终点,length是边的权值//
treetype=array[1。
。
n-1]ofedge;
//定义一个基类型为edge的数组类型treetype,其元素个数为n-1个//
varnet:
adjmatrix;
//定义一个adjmatrix类型的变量net,图的邻接矩阵就存放在net中//
tree:
treetype;
//定义一个treetype类型的变量tree,tree中可以存放n-1条边的信息,包括起点、终点及权值。
在算法结束后,最小生成树的n-1条边就存放在tree中//
算法如下(设n为构造的出发点):
procedureprim(net:
adjmatrix;vartree:
treetype);
//过程首部。
参数的含义是:
值参数net传递图的邻接矩阵,变参tree指明最小生成树的存放地址//
begin
forv:
=1ton-1do
//此循环将顶点n与图中其它n-1个顶点形成的n-1条边存放在变量tree中//
[tree[v]。
beg:
=n;
tree[v]。
en:
=v;
tree[v]。
length:
=net[v]]
fork:
=1ton-1do
//此循环执行算法思想中的步骤2,循环体每执行一次,TE中将增加一条边,在算法中,这条增加的边存放在变量tree中的第k个元素上,可以这样认为,tree中从第1到第k号元素中存放了TE和U的信息。
注意:
在算法思想中我们特别提醒了TE和U的动态性,表现在算法中,这种动态性体现在循环变量k的变化上。
//
[min:
=tree[k]。
length;
forj:
=kton-1do
iftree[j]。
length [min: =tree[j]。 length; m: =j;] //上面两条语句用于搜索权值最小的边// v: =tree[m]。 en; //此语句记录刚加入TE中的边的终点,也即即将加入U中的顶点// edge: =tree[m]; tree[m]: =tree[k]; tree[k]: =edge; //上面三句用于将刚找到的边存储到变量tree的第k号元素上// forj: =k+1ton-1do //此循环用于更新tree中第k+1到第n-1号元素。 更新以后这些元素中的en子项是各不相同的,它们的全部就是集合V-U;beg子项则可以相同,但它们需满足两个条件: 一是应属于集合U;另一是beg子项和en子项行成的边,在所有与顶点en联系的边中权值应最小。 // [d: =net[v。 tree[j]。 en]; ifd length then[tree[j]。 length: =d; tree[j]。 beg: =v;] ] ] forj: =1ton-1do //此循环用于输出最小生成树// writeln(tree[j]。 beg,tree[j]。 en,tree[j]。 length); end; 3.4程序中算法的实现 3.4.1具体到本程序,在程序中调用了两个函数,一个用以输出邻接矩阵,另一个就是Prim算法。 以下一段代码即是Prim算法的核心部分: prim(intg[][max],intn) { intlowcost[max],closest[max]; inti,j,k,min; for(i=2;i<=n;i++)/*n个顶点,n-1条边*/ { 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++)/*寻找满足边的一个顶点在U,另一个顶点在V的最小边*/ 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"); } } 3.4.2下面的代码实现的邻接矩阵的输出: voidprg(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("inf\t"); else printf("%d\t",g[i][j]); } printf("\n"); } 3.5有关技术的讨论 算法是指完成一个任务准确而完整的描述。 也就是说给定初始状态或输入数据,经过计算机程序的有限次运算,能够得出所要求或期望的终止状态或输出数据。 最小生成树是数据结构中图的一种重要应用,它的要求是从一个带权无向完全图中选择n-1条边并使这个图仍然连通,也即得到了一棵生成树,同时还要考虑使树的权最小。 为了得到最小生成树,人们设计了很多算法,最著名的有prim算法和kruskal算法。 其中prim算法的精巧之处在于对求权值最小的边这一问题的分解,从而大大减小了计算量。 让算法的时间复杂度大幅度减小。 Prim算法是贪心算法这类算法中一种非常典型的算发,所谓贪心法的基本思路, 即从问题的某一个初始解出发逐步逼近给定的目标,以尽可能快的地求得更好的解。 当达到某算法中的某一步不能再继续前进时,算法停止。 贪心算法总是作出在当前看来最好的选择。 也就是说贪心算法并不从整体最优考虑,它所作出的选择只是在某种意义上的局部最优选择。 当然,希望贪心算法得到的最终结果也是整体最优的。 虽然贪心算法不能对所有问题都得到整体最优解,但对许多问题它能产生整体最优解。 在一些情况下,即使贪心算法不能得到整体最优解,其最终结果却是最优解的很好近似。 在现实世界中,我们可以将问题分为两大类。 其中一类被称为P类问题,它存在有效算法,可求得最优解;另一类问题被称为NPC类问题,这类问题到目前为止人们尚未找到求得最优解的有效算法,这就需要每一位程序设计人员根据自己对题目的理解设计出求较优解的方法。 在现实生活中,P类问题是十分有限的,而NPC类问题则是普遍的、广泛的。 Prim算法就是求解P类问题的一种算法。 贪心算法中的最小生成树问题的prim算法,除了解决小区中网线铺设的问题,还可以用来解决机关单位、公司、学校等地方的各种管线铺设的问题。 这说明了贪心算法在解决实际问题中的应用是十分广泛和重要的。 其他非常有名的贪心算法的问题除了最短路径的问题外还有背包问题等。 4.程序实现 4.1完整的源代码 #include #defineinf9999 #definemax40 prim(intg[][max],intn) { intlowcost[max],closest[max]; inti,j,k,min; for(i=2;i<=n;i++)/*n个顶点,n-1条边*/ { 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++)/*寻找满足边的一个顶点在U,另一个顶点在V的最小边*/ 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"); } } voidprg(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("inf\t"); else printf("%d\t",g[i][j]); } printf("\n"); } main() { intg[max][max],n,e,weight,k,i,j,v1,v2;/*建立无向图*/ printf("inputthenumberofvertexandedge: "); scanf("%d%d",&n,&e);/*初始化矩阵*/ for(i=1;i<=n;i++) for(j=1;j<=n;j++) { if(i==j) g[i][j]=0; else g[i][j]=inf; } for(k=1;k<=e;k++) { printf("inputthestartpoint,destinationandweightedvalueofof%dthedge: ",k); scanf("%d%d%d",&v1,&v2,&weight); g[v1][v2]=weight; g[v2][v1]=weight; } printf("theadjacencymatrix: \n"); prg(g,n); printf("MST: \n"); prim(g,n); } 4.2运行结果 程序开始运行后,出现如下界面 这时可以输入无向图的顶点个数和边的条数。 中间用空格隔开。 程序中设定了顶点数不超过40,有需要可以很方便的更改。 输入完毕后回车,此处随意输入了简单数据。 出现如下界面: 这时可以输入每一条边的起点和终点以及它的权值,中间也用空格隔开,一条一条的输入完,每输一条边的信息就按一次回车。 输入的数据如下: 输入完成后,结果如下: 程序成功输出了无向图的邻接矩阵和最小生成树中的所有边。 原定目标达到,程序运行成功。 5设计体会 在设计这个程序的过程中,首先分析问题,问题给的比较实际具体,通过对问题的分析,得知这个问题的数学模型就是在无向图中求解最小生成树的问题。 对于这一类的问题,算法已经非常成熟,只是怎么把它具体应用,以及实现的问题。 在这个具体的小区铺设网线的问题中,我从两种最经典的算法: Prim算法和Kruscal算法,选用了前者,因为它更适合这个实际问题。 在程序的编写过程中,我没有使用结构体,而是使用了两个数组来分别存放顶点和边的信息,最终达到的效果一样,却可以使程序更易于理解。 在程序的设计过程中,也遇到了不少问题,好在问题本身的解题思路并不复杂,相关的算法在书上也有详细的介绍。 出现的问题也都是在编程方面的问题,如格式不正确之类,经过细心的排查,最后程序可以运行了。 6结束语 通过这次的课程设计,学到了很多东西,把课堂上面学到的算法应用到了实际的问题之中。 通过这种应用,也提高了自己的编程能力,对Prim算法的理解也有了进一步的加深。 参考文献 [1]严蔚敏,吴伟民.《数据结构》,清华大学出版社,2001年1月. [2]张颖江,胡燕.《C语言程序设计》,科学出版社,1998年7月. [3]谭浩强.《C程序设计》,清华大学出版社,1999年12月.
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 基于 最小 生成 小区 网线 铺设 问题 实现