最小生成树是指一个有 n 个结点的连通图的生成树是原图的极小连通子图,且包含原图中的所有 n 个结点,并且有保持图连通的最少的边。
Kruskal算法:克鲁斯卡尔算法(Kruskal's algorithm)是两个经典的最小生成树算法的较为简单理解的一个。这里面充分体现了贪心算法的精髓。大致的流程可以用一个图来表示。这里的图的选择借用了Wikipedia上的那个。非常清晰且直观。
思路:将所有点分为标记点和未标记点。每次从所有边中选择最短的一条边且这两条边与已选择的其他边不构成回路,并将两条边所对应的点纳入标记点,重复以上过程,直到所有点均为标记点。
分析:
1、选取最短边(1,2),将1,2纳入标记点。
2、从剩下的边中选取路径长度最短的边(2,4)。
3、选择最短的路径(0,1)。
4、此时如果选择(1,4)这条路径,就会形成回路,所以应选择(4,5)。
5、最后选择(1,3)这条路径。
代码实现:
import java.util.HashSet;
import java.util.Set;
public class Kruskal {
final static int N = 10000;
static int[][] matrix = new int[6][6];
public static void main(String[] args) {
matrix[0] = new int[] { N, 3, 5, N, N, N };
matrix[1] = new int[] { 3, N, 2, 7, 4, N };
matrix[2] = new int[] { 5, 2, N, N, 3, N };
matrix[3] = new int[] { N, 7, N, N, N, 8 };
matrix[4] = new int[] { N, 4, 3, N, N, 5 };
matrix[5] = new int[] { N, N, N, 8, 4, N };
// 建立标记点集合
Set<Integer> marked = new HashSet<>();
// 建立未标记点集合
Set<Integer> unMarked = new HashSet<>();
for (int i = 0; i < 6; i++)
unMarked.add(i);
// 选择最小边
int order=1;
while (!unMarked.isEmpty()) {
int minLength = 10000;
int p = 0, q = 0;
// 寻找最短路径
for (int i = 0; i < 6; i++) {
for (int j = 0; j < 6; j++) {
// 如果两点都属于标记点,在选择的话就会形成回路
if (matrix[i][j] < minLength && !(marked.contains(i) && marked.contains(j))) {
p = i;
q = j;
minLength = matrix[i][j];
}
}
}
if (!marked.contains(p)) {
marked.add(p);
unMarked.remove(p);
}
if (!marked.contains(q)) {
marked.add(q);
unMarked.remove(q);
}
System.out.println("第"+(order++)+"次选择的路径是("+p+","+q+")");
}
}
}