标签:操作 之间 另一个 邻接 连接 div 打印 下标 中心
普利姆算法
形象问题:几个村庄之间有N条路,要再路边修下水管道,求在那些路上修管道能在全部村庄连通的基础上使修的管道最短
中心思想:从一个顶点逐渐连接到全部顶点;在连接过程中找权最小的边加入生成树中
方法
1 //G是一个图结构体: 2 //numVertexes:顶点个数 3 //arc:邻接矩阵 4 void MinSpanTree_prim(MGraph G){ 5 int min , i , j , k; 6 int adjvax[MAXVEX];//到该位置对应顶点的最短路径的边的另一个顶点【方便找到边后打印这条边的两个顶点下标】 7 int lowcost[MAXVEX];//连接到下标对应顶点的边的最小权【为0表示已经找到;INFINITY表示还没找到;其他表示:目前为止的值】 8 //既然说是目前为止,是因为以后连接到其他顶点,还会添加可选择的边;在这些新加的边中可能会刷新连接它的边的权最小记录 9 10 lowcost[0]=0;//第一个顶点作为最小生成树的根,权直接为0 11 adjvax[0]=0;//第一个顶点先加入 12 13 //初始化操作 14 for(i=1;i<G.numVertexes;i++){ 15 lowcost[i]=G.arc[0][i];//将邻接矩阵第0行所有权值加入数组(从第一个顶点开始到其他顶点的权) 16 adjvax[i]=0;//初始化全部为第一个顶点的下标 17 } 18 19 //开始构建最下生成树 20 for(i=1;i<G.numVertexes;i++){//连接N个顶点,找N-1条边,分别从一个顶点找到其他N-1个顶点 21 min = INFINITY;//记录最小权值;初始化为65535; 22 j=1;//循环使用的索引值 23 k=0;//记录这次连接到的顶点的下标 24 25 //遍历全部顶点 26 while(j<G.numVertexes){//找到可连接的最小权 27 if(lowcost[j]!=0 && lowcost[j]<min){ 28 min=lowcost[j]; 29 k=j;//将找到的最小权值下标存入k; 30 } 31 j++; 32 } 33 34 printf("(%d,%d) ",adjcex[k],k);//打印当前顶点边中权值最小的边;adjcex[k],边的起始下标;k,当前位置 35 lowcost[k]=0;//将当前顶点的权值设置为0,表示此顶点已经连接到生成树中,继续进行连接下一个顶点 36 37 //邻接矩阵k行逐个遍历全部顶点 38 for(j=1;j<G.numVertexes;j++){ 39 if(lowcost[j]!=0 && G.[k][j] < lowcost[j]){ 40 lowcost[j]=G.arc[k][j];//刚刚连接的顶点下标k,连接到j位置顶点的权小于原先连接到j位置的权;那么就刷新连接他的最小权 41 adjvax[j]=k;//将刷新连接j位置最小权的顶点的下标记录到adjvax数组j位置下;利用该值打印这条权最小记录的边:(adjvax[k],k) 42 } 43 } 44 } 45 }
克鲁斯卡尔算法
直接去找权最小的边来构建生成树(构建过程中只要避免构成环即可)
方法
1 int find(int *parent,int f){ 2 while(parent[f]>0){ 3 f=parent[f]; 4 } 5 return f; 6 } 7 //parent数组:存储当前位置对应顶点在一棵树上的另一个顶点的对应下标 8 //所以刚开始时,存储下标对应的顶点是与自身位置对应顶点是直接相连的 9 //当这个位置构建最小生成树会直接相连一个顶点以上时,那么下一个连接顶点下标会存储在第一个连接下标顶点对应位置 10 //例如:0下标顶点构建最小生成树时会连接1下标和3下标两个顶点对应位置顶点;那么:parent[0]=1;parent[1]=3;或者parent[0]=3;parent[3]=1 11 //总之parent数组中将同一颗树顶点的下标利用类似链表的方法连接在一起; 12 //给f传入一颗树任意顶点对应的下标返回的值(x)都是一样的;并且在parent[x]这个位置是存放这颗树下一次新加的顶点下标的 13 14 //Kruskal算法生成最小生成树 15 void MiniSpanTree_Kruskal(MGraph G){ 16 int i,n,m; 17 Edge edges[MAGEDGE];//定义边集数组 18 int parent[MAGEDGE];//定义parent数组用来判断边与边是否形成环路 19 20 for(i=0;i<G.numVertexes;i++){ 21 parent[i]=0; 22 } 23 for(i=0;i<G.numEdges;i++){ 24 //edges:边集数组;边的结构:begin,起点;end,终点;weight,这条边的权 25 //n得到的是edges[i].begin这个下标所属树下一次新加顶点下标在prent数组中存储位置 26 //m得到的值也有edges[i].end顶点所属树的相同作用 27 //所以m==n就说明两顶点属于同一颗树(已经间接连接了,不需要再重复直接连接了;也就是不要形成环路) 28 //只有所属不同树时才同时有添加的能力,合并两棵树相当于要用掉一棵树的添加能力,合并后的数的添加能力就要原先被添加树承担 29 n=find(parent,edges[i].begin); 30 m=find(parent,edges[i].end); 31 if(n!=m){//如果n==m,则形成环路 32 parent[n]=m;//将此边的结尾顶点放入下标起点的parent数组中,表示此顶点已经在生成树集合中 33 printf("(%d,%d)%d ",edges[i].begin,edges[i].end,edges[i].weight); 34 } 35 } 36 }
标签:操作 之间 另一个 邻接 连接 div 打印 下标 中心
原文地址:https://www.cnblogs.com/TianLiang-2000/p/12861241.html