图论及其应用论文姓名:xxx学号:xxx专业:xxx图论在高校互联校内网建设的应用摘要图论和我们的生活其实是息息相关的,我们在生活中处处可见图论的实际应用。特别的,图论对我们通信专业以后的工作也有着极大的帮助。在以后的工作中也会时时用到图论的相关知识。本论文的主旨是利用相关的图论知识来解决重庆几所高校建立互联校内网的问题。主要是为了能使各重庆高校的学生能够免费共享高校的学习资源。从而促进各高校学生的共同发展。本文中,解决重庆几所高校建立互联校内网主要应用的是求图的最小生成树的方法。而求图的最小生成树有两种算法,一种是Prim(普里姆)算法,另一种是Kruskal(克鲁斯卡尔)算法。本文通过将高校转换成连通图,再将连通图转换成邻接矩阵。在C++上,通过输入结点和权值,用普里姆算法获得权值最小边来得到最小生成树,从而在保证各个地点之间能连通的情况下节省所需费用。关键字:最小生成树、PRIM算法、邻接矩阵、高校互联校内网建设1.连通图(1)概述在图论中,连通图基于连通的概念。在一个无向图G中,若从顶点vi到顶点vj有路径相连(当然从vj到vi也一定有路径),则称vi和vj是连通的。如果G是有向图,那么连接vi和vj的路径中所有的边都必须同向。如果图中任意两点都是连通的,那么图被称作连通图。图的连通性是图的基本性质。(2)严格定义对一个图G=(V,E)中的两点x和y,若存在交替的顶点和边的序列Γ=(x=v0-e1-v1-e2-...-ek-(vk+1)=y)(在有向图中要求有向边vi−(vi+1)属于E),则两点x和y是连通的。Γ是一条x到y的连通路径,x和y分别是起点和终点。当x=y时,Γ被称为回路。如果通路Γ中的边两两不同,则Γ是一条简单通路,否则为一条复杂通路。如果图G中每两点间皆连通,则G是连通图。(3)相关概念连通分量:无向图G的一个极大连通子图称为G的一个连通分量(或连通分支)。连通图只有一个连通分量,即其自身;非连通的无向图有多个连通分量。强连通图:有向图G=(V,E)中,若对于V中任意两个不同的顶点x和y,都存在从x到y以及从y到x的路径,则称G是强连通图。相应地有强连通分量的概念。强连通图只有一个强连通分量,即是其自身;非强连通的有向图有多个强连分量。弱连通图:将有向图的所有的有向边替换为无向边,所得到的图称为原图的基图。如果一个有向图的基图是连通图,则有向图是弱连通图。初级通路:通路中所有的顶点互不相同。初级通路必为简单通路,但反之不真。(4)性质一个无向图G=(V,E)是连通的,那么边的数目大于等于顶点的数目减一:|E|=|V|-1,而反之不成立。如果G=(V,E)是有向图,那么它是强连通图的必要条件是边的数目大于等于顶点的数目:|E|=|V|,而反之不成立。没有回路的无向图是连通的当且仅当它是树,即等价于:|E|=|V|-1。2.最小生成树(1)树树包含n(n=0)个节点。当n=0时表示为空树。其定义如下:T=(D,R)其中,D为树中节点的有限集合,关系R满足一下条件:①有且仅有一个节点k0属于D,它对于关系R来说没有前趋节点,结点k0称作树的根结点。②除根结点k0之外,D中的每个结点仅有一个前趋结点,但可以有过个后继结点。③D中可以有多个终端结点。即除根结点无父结点,其余各结点都有一个父结点和n(n=0)个子结点。(2)邻接矩阵图的矩阵表示,本文中只用到了邻接矩阵,故在这只提出邻接矩阵的定义,及其图在邻接矩阵中的表示。设图A=(V,E)是一个有n个顶点的图,图的邻接矩阵是一个二维数组A.edge[n][n],用来存放顶点的信息和边或弧的信息。是表示顶点之间相邻关系的矩阵。设G=(V,E)是一个图,其中V={v1,v2,…,vn}。G的邻接矩阵是一个具有下列性质的n阶方阵:①无向图的邻接矩阵是对称的;有向图的邻接矩阵可能是不对称的。②无向图的邻接矩阵中第i行第j列表示i结点到j结点的度即权值,可以表示为某一具体应用的数据。也表示i结点是否与j结点连通。(3)最小生成树在一给定的无向图G=(V,E)中(u,v)代表连接顶点u与顶点v的边(即),而w(u,v)代表此边的权重,若存在T为E的子集(即)且为无循环图,使得的w(T)最小则此T为G的最小生成树。3.prim算法思想:首先,选择带最小的边,把它放进生成树里,相继添加带权最小的边,这些边与已在树立的顶点相关联,并且不与已在数理的边形成圈,当已经添加了n-1条边为止步骤:假设V是图中顶点的集合,E是图中边的集合,TE为最小生成树中的边的集合,则prim算法通过以下步骤可以得到最小生成树:(1)初始化:U={u0},TE={f}。此步骤设立一个只有结点u0的结点集U和一个空的边集TE作为最小生成树的初始形态,在随后的算法执行中,这个形态会不断的发生变化,直到得到最小生成树为止。(2)在所有u∈U,v∈V-U的边(u,v)∈E中,找一条权最小的边(u0,v0),将此边加进集合TE中,并将此边的非U中顶点加入U中。此步骤的功能是在边集E中找一条边,要求这条边满足以下条件:首先边的两个顶点要分别在顶点集合U和V-U中,其次边的权要最小。找到这条边以后,把这条边放到边集TE中,并把这条边上不在U中的那个顶点加入到U中。这一步骤在算法中应执行多次,每执行一次,集合TE和U都将发生变化,分别增加一条边和一个顶点,因此,TE和U是两个动态的集合,这一点在理解算法时要密切注意。(3)如果U=V,则算法结束;否则重复步骤2。可以把本步骤看成循环终止条件。我们可以算出当U=V时,步骤2共执行了n-1次(设n为图中顶点的数目),TE中也增加了n-1条边,这n-1条边就是需要求出的最小生成树的边。4.实际问题及其解决现有:重庆大学,西南大学,西南政法大学,重庆师范大学,重庆邮电大学5所高校,要求把他们的校内网进行互联,以组建一个更大的校园网络。在发费最少的情况下进行光缆的铺设。根据实际测量地图的得到的各学校之间的直线距离图:由于每公里光缆造价相同,故可以用实际距离代替造价作为权重。实际情况缩略图:设:重庆邮电大学V1重庆大学V2重庆师范大学V3西南大学V4西南政法大学V5输入程序运行得到结果:解决问题得到结果:5.总结通过对prim算法编写的C程序我们可以轻易地得到在发费最少的情况下进行光缆的铺设的路径。这大大的节约了成本和时间,是对实际问题的一次生动尝试。同时这个程序也可以进行相应的改善和推广,以利于我们的工作实践。参考文献【1】《图论及其算法》,殷剑宏等,中国科学技术大学出版社。【2】《C语言程序设计》(第三版),谭浩强,清华大学出版社。【3】《数据结构》(C语言版),严蔚敏吴伟民,清华大学出版社。程序#includestdio.h#definemaxnum10#definemaxvalue88typedefstruct//定义存放各节点间边的权值的二位数组为新的数据类型可称为图{intv[maxvalue][maxvalue];}mgraph;//该数据类型用标识符mgraph表示mgraphinput(intn)//数据输入函数用于输入各节点间边的权值{mgraphx;//定义x为mgraph类型while(n=0||nmaxnum)//控制输入出错重新执行{printf(输入有误,请重新输入:);scanf(%d,&n);}for(inti=1;i=n;i++)//双层循环控制每个节点到其他各节点的权值{for(intj=0;j=n;j++){inttemp;//定义临时变量用于存放输入权值便于接下的过滤操作if(i==j)//各节点到自身的权重赋为0x.v[i][j]=0;elseif(ij)//赋值其他各点到比其大的下标的节点{printf(请输入节点%d到节点%d的权:,i,j);scanf(%d,&temp);//将输入临时存放在tempwhile(temp==0||temp-1)//过滤输入数据{printf(输入有误,请重新输入:\n);printf(请输入%d到%d的权:,i,j);scanf(%d,&temp);}if(temp0)//将符合要求数据赋值给tempx.v[i][j]=temp;else//temp=-1时将权重赋值最大值88x.v[i][j]=maxvalue;}else//ij由于权重是对称的即呈上三角或下三角分布故只需将i,j对换即可x.v[i][j]=x.v[j][i];}printf(\n);}returnx;//返回图x}voidprint(mgraphg,intn)//打印函数{inti,j;//定义整型i,jprintf();//打印美观需要for(i=1;i=n;i++)printf(%2d,i);printf(\n);for(i=1;i=n;i++)//双层循环按矩阵方式打印输出各节点间权值{printf(%d,i);for(j=1;j=n;j++)printf(%2d,g.v[i][j]);printf(\n);}}voidprim(mgraphg,intk,intn)//核心算法Prim算法实现函数{inti,j,min,p;//定义整型变量i,j用于循环min和p分别用于临时存放最小权值及其下标struct//定义型类型数据closedge[]用于临时存放下标和最小边{intadjvex;intlowcost;}closedge[maxnum];for(i=1;i=n;i++)//初始化辅助数组if(i!=k){closedge[i].adjvex=k;closedge[i].lowcost=g.v[k][i];}closedge[k].lowcost=0;//将节点加入生成树中for(i=1;in;i++)//循环比较最小权值且将最小权值的点加入生成树中并打印输出{p=1;//初始化pmin=maxvalue;//初始化最小权值for(j=1;j=n;j++)//循环n次比较最小权值if(closedge[j].lowcost!=0&&closedge[j].lowcostmin)//当前节点不在已生成树中且权值最下{min=closedge[j].lowcost;//替换最小权值为当前节点的权值p=j;//记录该节点下标}printf(%d__%d\n,closedge[p].adjvex,p,min);//打印最小的权值的下标和最小边closedge[p].lowcost=0;//将该节点加入生成树中for(j=1;j=n;j++)//刷新临时存放空间if((g.v[p][j])(closedge[j].lowcost)){closedge[j].lowcost=g.v[p][j];//赋值最小边closedge[j].adjvex=p;//赋值最小边对应下标}}}intmain()//主函数{intn,start;//定义整型n,start表示节点数和开始节点printf(请输入节点数(不大于10):);scanf(%d,&n);mgraphred;//定义图redred=input(n);//调用输入函数用户输入数据print(red,n);//调用输出函数打印输出所输入的数据printf(请输入开始节点:);scanf(%d,&start);prim(red,start,n);//调用prim函数实现prim算法求最小生成树return0;}