1,普里姆算法(Prim)
- 此算法可以称为“加点法”,每次迭代选择代价最小的边对应的点,加入到最小生成树中。算法从某一个顶点s开始,逐渐长大覆盖整个连通网的所有顶点。
- 具体步骤如下
- 图的所有顶点集合为V;初始令集合u={s},v=V−u;
- 在两个集合u,v能够组成的边中,选择一条代价最小的边(u0,v0),加入到最小生成树中,并把v0并入到集合u中。
- 重复上述步骤,直到最小生成树有n-1条边或者n个顶点为止。
- 具体操作如图所示
Java代码如下所示(仅供参考):
import java.util.ArrayList;
import java.util.List;
/**
* @author biHuGang
* @date 2020/4/28
*/
public class DemoPrim {
static int[][] graph;
//存放已经加入到最小生成树的边
static List<Integer> arr = new ArrayList<>();
static boolean[] vis;
public static void main(String[] args) {
vis = new boolean[6];
//邻接矩阵
graph = new int[][]{
{0, 6, 1, 5, 0, 0},
{6, 0, 5, 0, 3, 0},
{1, 5, 0, 5, 6, 4},
{5, 0, 5, 0, 0, 2},
{0, 3, 6, 0, 0, 6},
{0, 0, 4, 2, 6, 0}
};
int ans = prim(0);
System.out.println(ans);
}
private static int prim(int start) {
int ans = 0;
for (int i = 0; i < 5; i++) {
//将该节点加入到集合中
arr.add(start);
//标记
vis[start] = true;
int val = Integer.MAX_VALUE;
//寻找最小边
for (int row : arr) {
for (int j = 0; j < 6; j++) {
if (!vis[j]) {
if (graph[row][j] < val && graph[row][j] > 0) {
start = j;
val = graph[row][j];
}
}
}
}
ans += val;
}
return ans;
}
}
// ans = 15;
2,克鲁斯卡尔算法(Kruskal)
- 此算法可以称为“加边法”,初始最小生成树边数为0,每迭代一次就选择一条满足条件的最小代价边,加入到最小生成树的边集合里。
- 把图中的所有边按代价从小到大排序;
- 把图中的n个顶点看成独立的n棵树组成的森林;
- 按权值从小到大选择边,所选的边连接的两个顶点ui,vi,应属于两颗不同的树,则成为最小生成树的一条边,并将这两颗树合并作为一颗树。
- 重复(3),直到所有顶点都在一颗树内或者有n-1条边为止。
- 该算法可以借助并查集来实现
- 如果对并查集还不了解的,可以看我的另一篇博客—并查集Java实现
Java代码如下所示(仅供参考)
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
* @author biHuGang
* @date 2020/4/28
*/
public class DemoKruskal {
static int[][] graph;
static List<Node> arr = new ArrayList<>();
static int[] parent;
static int[] rank;
static int ans = 0;
public static void main(String[] args) {
parent = new int[6];
rank = new int[6];
Arrays.fill(parent, -1);
Arrays.fill(rank, 0);
graph = new int[][]{
{0, 6, 1, 5, 0, 0},
{0, 0, 5, 0, 3, 0},
{0, 0, 0, 5, 6, 4},
{0, 0, 0, 0, 0, 2},
{0, 0, 0, 0, 0, 6},
{0, 0, 0, 0, 0, 0}
};
for (int i = 0; i < 6; i++) {
for (int j = 0; j < 6; j++) {
if (graph[i][j] != 0) {
arr.add(new Node(i, j, graph[i][j]));
}
}
}
Collections.sort(arr);
for (int i = 0; i < arr.size(); i++) {
Node node = arr.get(i);
union_root(node);
}
System.out.println(ans);
}
//合并根
private static void union_root(Node node) {
int x_root = find_root(node.x);
int y_root = find_root(node.y);
//如果在同一棵树上,则不做任何操作
if (x_root == y_root) {
return;
} else {
//rank数组优化
if (rank[x_root] > rank[y_root]) {
parent[y_root] = x_root;
} else if (rank[x_root] < rank[y_root]) {
parent[x_root] = y_root;
} else {
parent[x_root] = y_root;
rank[y_root]++;
}
ans += node.val;
}
}
//寻找根(路径压缩递归版)
private static int find_root(int x) {
if (parent[x] == -1) return x;
return parent[x] = find_root(parent[x]);
}
//寻找根(路径压缩非递归版)
/*private static int find_root(int x) {
int root = x;
while (parent[root] != -1){
root = parent[root];
}
while (parent[x] != -1){
int r = parent[x];
parent[x] = root;
x = r;
}
return root;
}*/
}
class Node implements Comparable<Node> {
int x;
int y;
int val;
public Node(int x, int y, int val) {
this.x = x;
this.y = y;
this.val = val;
}
@Override
public int compareTo(Node o) {
return this.val - o.val;
}
}
// ans = 15;
转载:勿在浮沙筑高台 http://blog.csdn.net/luoshixian099/article/details/51908175