最小生成树问题
前提
在一给定的无向图G = (V, E) 中,(u, v) 代表连接顶点 u 与顶点 v 的边(即),而 w(u, v) 代表此边的权重,若存在 T 为 E 的子集且为无循环图,使得联通所有结点的的 w(T) 最小,则此 T 为 G 的最小生成树。
最小生成树其实是最小权重生成树的简称。
先回忆回忆什么是树、什么是图、什么是最小生成树。
1 描述最小生成树问题算法的输入、输出
1.1 最小生成树问题算法的输入:由实际生活中的点和边构成的图,如基电站和电缆线路、景点和公路等抽象化出来的图;
1.2 最小生成树问题算法的输出:由输入的图经过Prim算法或者Kruskal 算法等处理最终得到一个各条边权值之和最小的树,而得到的这棵树叫做最小生成树,该生成树往往是修公路的费用最小化的修路方式、修电站的通信的电线的费用最小化的修造方式。
1.3 最小生成树要解决的两个问题:
(1)尽可能选取权值小的边,但不能构成回路;
(2)选取n-1条恰当的边以连接网的n个顶点。
1.4 构成网的一棵最小生成树,即:在e条带权的边中选取n-1条边(不构成回路),使“权值之和”为最小。
2 普里姆算法(Prim)
2.1 本质:加点法
2.2 基本思想:
取图中任意一个顶点V作为生成树的根,之后往生成树上添加新的顶点W。在添加的顶点W和已经在生成树上的顶点V之间必定存在一条边,该边的权值在所有连通项点V和W之间的边中取值为最小。
之后继续往生成树上添加顶点,直至生成树上含有n个顶点为止。
2.3 具体做法:
在生成树的构造过程中,让连通图中n个顶点分属两个集合:已经加入到生成树上的顶点集合U和(原连通图上)还没加入到生成树上的顶点集合V-U;每次在V-U集合里选中一个和生成树上某一个顶点连线中权值最小的,将此顶点加入到生成树里。
2.4 实例:
(1)如下带权无向连通图1:
(2)从顶点a开始加点:
说明:可能考虑的边的权值,这一列的数据,标志为红色是指这权值为X1的边的两个顶点为U集合;标志为蓝色是指这权值为X2的边再次被遇到,但这边不能在本次最小生成树;为空,则表示Prim算法结束。
(3)最终得到最小生成树,如下图中的用红色边连通的顶点所构成的树:
(4)主要代码(用java实现):
public static void onChangeVertex(Vertex vertex) {
visitedVertexs.add(vertex); //添加初始节点,作为默认的开始节点
leftedVertexs.remove(vertex);
}
public static Vertex findOneVertex(Graph g) {
int minValue = Integer.MAX_VALUE;
Vertex findVertex = new Vertex();
Edge findEdge = new Edge();
for(int i=0;i<visitedVertexs.size();i++) {
for(int j=0;j<leftedVertexs.size();j++) {
Vertex v1 = visitedVertexs.get(i);
Vertex v2 = leftedVertexs.get(j); //获取两个顶点的名称
for(int k=0;k<g.edge.length;k++) {
String startName = g.edge[k].startVertex.vName;
String endName = g.edge[k].endVertex.vName;
if((v1.vName.equals(startName) && v2.vName.equals(endName)) ||(v1.vName.equals(endName) && v2.vName.equals(startName))){
if(g.edge[k].weight < minValue) {
findEdge = g.edge[k];
minValue = g.edge[k].weight;
if(leftedVertexs.contains(v1)){
//会调用对象的equals方法比较对象,需重写equals方法
findVertex = v1;
}else if(leftedVertexs.contains(v2)){
findVertex = v2;
}
}
}
}
}
}
g.minWeight+= minValue;
searchEdges.add(findEdge);
return findVertex;
}
public static void prim(Graph g) {
while(leftedVertexs.size()>0){
//直到剩余节点集为空时结束循环
Vertex findVertex = findOneVertex(g);
onChangeVertex(findVertex);
}
System.out.print("\n最短路径包含的边: ");
for(int i=0;i<searchEdges.size();i++) {
System.out.