Kruscal算法实现最小生成树
主方法
1 import java.util.Arrays; 2 import java.util.Comparator; 3 import java.util.Scanner; 4 5 public class Solution4 { 6 static class Edge{ 7 int u, v; 8 int cost; 9 }; 10 public static Edge[] edges = new Edge[10010]; // 存储所有的边的数据 11 public static int[] root = new int[110]; // 存储每个结点所在集合 12 public static int e, v; // 分别表示边数和顶点数 13 14 public static void main(String[] args) { 15 Scanner in = new Scanner(System.in); 16 while((e = in.nextInt()) != 0){ 17 // 初始化每个顶点所在的集合为自己单独所处的集合 18 for(int i = 0; i < 110; i++){ 19 root[i] = i; 20 } 21 // 读入所有边的数据 22 v = in.nextInt(); 23 int a, b; 24 for(int i = 0; i < e; i++){ 25 edges[i] = new Edge(); 26 edges[i].u = in.nextInt(); 27 edges[i].v = in.nextInt(); 28 edges[i].cost = in.nextInt(); 29 } 30 31 // 进行 Kruscal 算法构建最小生成树 32 int price = Krusal(); 33 if(price == -1) 34 System.out.println("?"); 35 else 36 System.out.println(price); 37 } 38 39 } 40 }
Krusal()函数
1 // Kruscal 算法生成最小生成树 2 public static int Krusal(){ 3 // 对所有边进行排序 4 Arrays.sort(edges, 0, e, new Comparator<Edge>(){ 5 public int compare(Edge e1, Edge e2){ 6 return e1.cost - e2.cost; 7 } 8 }); 9 int cost = 0; // 总花费 10 int edgeCount = 0; // 当前已归纳的边数 11 // 遍历所有的边,统计当前生成树中边的数量 12 for(int i = 0; i < e; i++){ 13 // 判断 边的链各个顶点是否属于同一个集合 14 int uRoot = findRoot(edges[i].u); 15 int vRoot = findRoot(edges[i].v); 16 // 如果不输于则合并 17 if(uRoot != vRoot){ 18 root[vRoot] = uRoot; 19 cost += edges[i].cost; 20 edgeCount++; 21 if(edgeCount == v - 1) 22 return cost; 23 } 24 // 如果边的数量等于顶点数减一,那么可以退出循环 25 } 26 return -1; 27 28 }
这里主要注意的并查集的findRoot()方法,非常巧妙,内部使用了一个递归来压缩路径
1 private static int findRoot(int u) { 2 if(root[u] == u) 3 return u; 4 int uRoot = findRoot(root[root[u]]); // 路径压缩 5 root[u] = uRoot; 6 return uRoot; 7 }
prim()算法实现最小生生成树
1 import java.util.Arrays; 2 import java.util.Scanner; 3 4 public class PrimTest { 5 // 构建最小生成树 6 public static int[][] G = new int[110][110]; // 村庄的图 7 public static boolean[] vis = new boolean[110]; // 判断某个村庄是否已经被访问过 8 public static int[] dis = new int[110]; // 存放每个村庄到当前生成树集合的距离 9 public static int e; 10 public static final int INF = 1 << 30; 11 public static int v; 12 13 public static void main(String[] args) { 14 // 读入数据 15 Scanner in = new Scanner(System.in); 16 17 e = in.nextInt(); 18 v = in.nextInt(); 19 for (int i = 0; i < v; i++) { 20 Arrays.fill(G[i], INF); 21 } 22 Arrays.fill(vis, false); 23 int a, b; 24 // 对这个数据进行prim最小生成树算法 25 for (int i = 0; i < e; i++) { 26 a = in.nextInt(); 27 b = in.nextInt(); 28 G[a - 1][b - 1] = in.nextInt(); 29 G[b - 1][a - 1] = G[a - 1][b - 1]; 30 } 31 32 // 如果仍有点的距离为 -1,说明不可达,输出? 33 int price = prim(0); 34 if (price == -1) 35 System.out.println("?"); 36 else 37 System.out.println(price); 38 } 39 }
prim()函数
1 private static int prim(int u) { 2 int price = 0; 3 // 初始化距离数组 4 Arrays.fill(dis, INF); 5 dis[u] = 0; 6 // 对每个村庄进行循环判断,每次选出其中一个点 7 for (int i = 0; i < v; i++) { 8 int min = INF, vil = -1; 9 for (int j = 0; j < v; j++) { 10 if (vis[j] == false && dis[j] < min) { 11 min = dis[j]; 12 vil = j; 13 } 14 } 15 if (min == INF) { 16 return -1; // 说明不可达 17 } 18 // 标记为已访问 19 vis[vil] = true; 20 price += dis[vil]; 21 // 更新剩下的dis[]值,更新这个村庄周边到当前生成树的最短距离 22 for (int j = 0; j < v; j++) { 23 if (vis[j] == false && G[vil][j] != INF && dis[j] > G[vil][j]) { 24 dis[j] = G[vil][j]; 25 } 26 } 27 } 28 return price; 29 }
原文地址:https://www.cnblogs.com/hi3254014978/p/12672367.html
时间: 2024-10-08 22:38:05