普利姆算法
问题描述
修路问题:现在有A,B,C,D,E,F,G七个村庄,道路四通八达,有一天为了交通便利,几个村庄就想修路,但是经济条件有限,道路却有很多条,我们要怎么知道在修最短路程的基础上又保证所有村庄都可以联通起来。
思路分析
这就是一个求最小生成树的问题,举例我们从A村开始修,这时候A可以修往(C B G)三个村,因为是修最短路径,如图所示A->G最短,我们就修往G村。此时修到了G村,我们在G这个村庄判断G可以修往的村庄,如图所示G可以修往(A B E F )但是此时去往A村庄的路已经通了,所以不考虑,如图所示除了A那就是G->B了,此时我们的路已经修道了B村,我们再判断可以修的路线并且排除已经修过的(A G),然后取最小值,依次类推,当我们修了n-1(7-1=6)条时,所有的村庄就已经修通啦。
代码实现(注释很清楚)
首先需要一个图结构保存各个村庄之间的权值(距离)
// 创建一个图存放节点的数据(节点数量 节点数据(名字)
// 节点间的权值)
class MGraph{
int verxs; // 表示图的节点个数
char[] data; // 存放节点的数据
int[][] weight; // 存放边 就是我们的领接矩阵
public MGraph(int verxs){
this.verxs = verxs;
data = new char[verxs];
weight = new int[verxs][verxs];
}
}
然后创建最小生成树
// 创建最小生成树
class MinTree{
// 创建图的领接矩阵
/**
* 创建最小数 你先得创建一个图 然后遍历图
* 得个最优的最小数
* @param graph 图对象
* @param verxs 顶点个数
* @param data 顶点的 值
* @param weight 图的领接矩阵
*/
public void createGraph(MGraph graph, int verxs
, char data[] ,int[][] weight ){
for (int i = 0 ; i < verxs; i++){
graph.data[i] = data[i];
for (int j = 0; j< verxs; j++){
graph.weight[i][j] = weight[i][j];
}
}
}
public void showGraph(MGraph graph){
for (int[] link : graph.weight) {
System.out.println(Arrays.toString(link));
}
}
/**
* 普利姆算法 得到最小生成树
* @param graph 图
* @param v 表示从图的第几个顶点开始遍历
*/
public void prim(MGraph graph,int v){
// visited[] 因为的判断村庄的路是否被修过
// 所有创建集合来记录
int[] visited = new int[graph.verxs];
// 当前节点设置为已访问
visited[v] = 1;
// h1 h2 用于记录最小权值目标的坐标
int h1 = -1;
int h2 = -1;
// 将minWeight设置为一个较大数在遍历时 会被替换
int minWeight = 10000;
// 因为有graph.verxs个顶点
// 所以有graph.verxs-1条边
for (int k = 0; k < graph.verxs-1; k++) {
// 确定每一次生成的子图
//用if判断确定每次要走的最小路径的两个几点
for (int i = 0; i < graph.verxs; i++) {
for (int j = 0; j < graph.verxs; j++) {
// 当前点如果为1下一个为0就说明j村庄
// 的路还没有修
// 同时要判断出时最短的一条路
if (visited[i] ==1 &&
visited[j] == 0&&
graph.weight[i][j] < minWeight){
//如果找到了这条路保存这条路的值
//并保存两点位置方便与后面遍历的
//路比较,循环结束最短路径就求出来了
minWeight = graph.weight[i][j];
h1 = i;
h2 = j;
}
}
}
//打印出来
System.out.println("边<"+graph.data[h1]
+","+graph.data[h2]+">权值"+minWeight);
// 修改村庄信息为已修过
visited[h2] = 1;
minWeight = 10000;
}
}
}
运行结果
边<A,G>权值2
边<G,B>权值3
边<G,E>权值4
边<E,F>权值5
边<F,D>权值4
边<A,C>权值7
总结
每次都求出最短路径,并且一个村庄的路只修一次,当修完(n-1)条路时,最短路径也就得出来了。普里姆算法的运行效率只与顶点数相关,而和边数无关。所以普里姆算法适合于解决边稠密的网。如果连通网中所含边的绸密度不高,则建议使用克鲁斯卡尔算法点击传送求最小生成树。
秃头萌新一枚 希望可以帮助到大家理解