1.最小生成树
(1)使图保持连通特性的最小代价,贪心策略
(2)应用:顶点表示城市,边表示两个城市之间的通信线路,n个城市之间最多n(n-1)/2条线路,把n个城市连接起来至少需要n-1条,则最小生成树表示建立通信的最佳方案
再如:电子元器件管脚相连,找出连线最少的方案
2.prim算法和kruskal算法
这两种方案使用普通二叉堆的情况下,很容易达到O(ElogV)的时间复杂度。通过斐波那契堆,prim算法可以达到O(E+VlogV)的运行时间,如果V远小于E的话,这是很大的改进。
3.prim算法
MST性质:G=(V,E)是连通图,U是V的真子集,若边(u,v)一个端点u在U里,另一个端点v不在U里(在V里),若(u,v)具有最小权值,那么一定存在G的一颗最小生成树包含边(u,v). prim算法就是利用这个性质的,
时间复杂度:邻接矩阵O(n^2) 二叉堆O(elogv) 斐波那契堆(e+vlogv)
我的理解:图G(V,E)的最小生成树T(U,E2) ;首先选定一个顶点作为树的根u0, 此时u0在U中不在V中,其他点到树 T 的最短距离 = 到 T 中任意点的最小距离,每次把最小距离另一端的点 v 加入 T中,把边(u,v)也加入T 中;因为T中加入新的点,所以更新各点到树T的最短距离,并在 V中删除点v ; 重复以上两步骤
最小生成树不是唯一的,但他们的权值是相等的
/**
* @Title: Prim.java
* @Package mini_span_tree_array
* @Description: TODO(prim算法实现最小生成树)
* @author LingLee
* @date 2017年3月17日 上午9:29:30
* @version V1.0
*/
package mini_span_tree_array;
/**
* @Title: Prim
* @Description: TODO(prim类)
*/
public class Prim {
static final int maxInt=Integer.MAX_VALUE;
public void primMST(int[][] weight,int vNum){
boolean[] inTree=new boolean[vNum+1];
int[] closest=new int[vNum+1];//代表与树T中相连最小权值边的点
for(int i=0;i<=vNum;i++){
closest[i]=1;
}
inTree[1]=true;//选第一个顶点为根
int sum=0;
System.out.println("树根选为:"+1);
for(int j=1;jweight[min_i][i]){
weight[1][i]=weight[min_i][i];//weight[1][i]永远保存i与树的最小距离
closest[i]=min_i;//节点I 与树的最小距离是 通过边 i min_i实现的
}
}
System.out.println();
sum+=weight[1][min_i];//加上权值
}
System.out.println("权值:"+sum);
}
}
/**
* @Title: Test.java
* @Package mini_span_tree_array
* @Description: TODO(test)
* @author LingLee
* @date 2017年3月17日 上午9:54:14
* @version V1.0
*/
package mini_span_tree_array;
/**
* @Title: Test
* @Description: TODO(测试类)
*/
public class Test {
public static void main(String[] args){
// ①
// / | /
// 6 1 5
// / | /
// ②-5--③--5--④
// / // /
// 3 6 4 2
// // //
// ⑤--6-⑥
//最小生成树为:
// ①
// |
// 1
// |
// ②-5--③ ④
// / / /
// 3 4 2
// / //
// ⑤ ⑥
//
int m=Integer.MAX_VALUE;
int[][] weight={{0, 0, 0, 0, 0, 0, 0},
{0, m, 6, 1, 5, m, m},
{0, 6, m, 5, m, 3, m},
{0, 1, 5, m, 5, 6, 4},
{0, 5, m, 5, m, m, 2},
{0, m, 3, 6, m, m, 6},
{0, m, m, 4, 2, 6, m}};//上图的矩阵
Prim p=new Prim();
p.primMST(weight, weight.length-1);
}
}
与prim判断节点的个数不同,kruskal针对的是边:所有点都在树T中,那么在图G中选择最小的边加入T中,该边将T中的两个点连起来;从图G中删除边;再重新选择最小的边,直到将T中所有节点都连接起来。
该方法更适合边稀疏的图,在添加边时应避免回路
用二叉堆来实现时间复杂度为O(eloge)