1.如今要选择这样一个生成树,也就是使总耗费最少。这个问题就是构造连通网的最小代价生成树(Minimum Cost Spanning Tree)简称为最小生成树的问题。一颗生成树的代价就是树上各边的代价之和。java
构造最小生成树的算法有多种。大多算法利用了最小生成树的下列简称为MST的特性:算法
假设N=(V,{E})是一个连通网,(N表明连通网,V表明网的各个顶点,E表明网的边),U是顶点集V的一个非空子集。若(u,v)是一条具备最小权值的边,其中u属于U,v属于V-U,则必存在一颗包含边(u,v)的最小生成树。数组
2.反证法证实上面MST特性:code
假设网N的任意一颗最小生成树都不包含(u,v).设T是连通网上的一颗最小生成树,当将边(u,v)加入T中时,由生成树的定义可知,T中必存在一条包含(u,v)的回路。排序
另外一方面,因为T是生成树,则在T中必存在一条(u1,v1),其中u1属于U,v1属于V-U,且u,u1,v,v1必有路径相通。删去(u1,v1)即可消除上述回路,同时获得另外一颗生成树T1。因为(u,v)的代价不高于(u1,v1),则T1的代价不高于T,T1是包含(u,v)的一颗最小生成树。由此可假设矛盾。索引
3.普里姆(prim)算法 get
假设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的最小生成树。io
为实现这个算法,须要附设一个辅助数组closedge,以记录从U到U-V具备最小代价的边。对每一个顶点vi属于V-U,在辅助数组中存在一个相应份量closedge[i-1],它包含两个域,其中lowcost存储该边上的权。vex存储附属在该边上的在U中的顶点。 class
/** * 普里姆算法,最小生成树, * 从图中第start个元素开始,生成最小树 */ public void prim(int start) { Integer vexNum = mVexs.length; //顶点的个数 int index = 0;//prim最小树的索引,即prims数组的索引 String[] prims = new String[vexNum]; //prim最小树的结果数组 int[] weights = new int[vexNum]; //顶点间的权值 prims[index++] = mVexs[start].data; //prim生成树的第一个顶点是从start开始的 /** * 初始化顶点的权值数组; * 将每一个顶点的权值初始化为第start个顶点到该顶点的权值 */ for (int i = 0; i < vexNum; i++) { weights[i] = getWeight(start, i); } for (int i = 0; i < vexNum; i++) { if (start == i) { continue; //终止本次循环,进行下一次循环,break终止for中的循环,进行循环下面的语句 } int j = 0, k = 0, min = INF; //在未被加入最小生成树的顶点中,找出权值最小的顶点 while (j < vexNum) { //当weights[j]=0时,意味着第j个顶点已经被排序过,或者说已经加入了最小生成树中 if (weights[j] != 0 & weights[j] < min) { min = weights[j]; k = j; //将最小权值的顶点赋给k } j++; } /** * 通过上面的while循环,则知在未被加入到最小生成树的顶点中,权值最小的是k * 将第k个顶点加入到prims数组中 */ prims[index++] = mVexs[k].data; //并将第k个顶点的权值标记为0,意味着第k个顶点已经被排序过了或者说被加入到了最小生成树的结果中 weights[k] = 0; //更新其余顶点到最小生成树中顶点的权值 for (j = 0; j < vexNum; j++) { //获取第k个顶点到第j个顶点的权值 int tmp = getWeight(k, j); //当第j个顶点未在最小生成树中,且第j个顶点到最小生成树中顶点的权值须要更新时,即加入k顶点后,已再也不是最小权值时 if (weights[j] != 0 && tmp < weights[j]) { weights[j] = tmp; } } } /** * 当prim最小生成树已经生成完毕时 * 计算最小生成树的权值 */ int sum = 0; //要从第2个元素开始,索引为1,由于要计算两顶点之间的权值 for (int i = 1; i < index; i++) { int min = INF; //或者去prims[i]顶点在顶点中的位置 int n = getPostion(prims[i]); for (int j = 0; j < i; j++) { int m = getPostion(prims[j]); int tmp = getWeight(m, n); if (tmp < min) { min = tmp; } } sum += min; } /** * 打印最小生成树 */ System.out.println("PRIM" + mVexs[start].data + "=" + sum); for (int i = 0; i < index; i++) { System.out.println(prims[i]); } }