最小生成树

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);
	}
}

最小生成树_第1张图片
4.kruskal方法

与prim判断节点的个数不同,kruskal针对的是边:所有点都在树T中,那么在图G中选择最小的边加入T中,该边将T中的两个点连起来;从图G中删除边;再重新选择最小的边,直到将T中所有节点都连接起来。

该方法更适合边稀疏的图,在添加边时应避免回路

用二叉堆来实现时间复杂度为O(eloge)


你可能感兴趣的:(数据结构和算法)