最小生成树的 Krusal 算法和 Prim 算法 Java 实现

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

最小生成树的 Krusal 算法和 Prim 算法 Java 实现的相关文章

最小生成树之Kruskal算法和Prim算法

依据图的深度优先遍历和广度优先遍历,能够用最少的边连接全部的顶点,并且不会形成回路. 这样的连接全部顶点并且路径唯一的树型结构称为生成树或扩展树.实际中.希望产生的生成树的全部边的权值和最小,称之为最小生成树. 常见的最小生成树算法有Kruskal算法和Prim算法. Kruskal算法每次选取权值最小的边.然后检查是否增加后形成回路,假设形成回路则须要放弃.终于构成最小生成树.n个顶点的图最小生成树过程例如以下: 边的权值升序排序. 选取全部未遍历的边中权值最小的边,推断增加后是否形成回路,若

Algorithm --&gt; Kruskal算法和Prim算法

最小生成树之Kruskal算法和Prim算法 根据图的深度优先遍历和广度优先遍历,可以用最少的边连接所有的顶点,而且不会形成回路.这种连接所有顶点并且路径唯一的树型结构称为生成树或扩展树.实际中,希望产生的生成树的所有边的权值和最小,称之为最小生成树.常见的最小生成树算法有Kruskal算法和Prim算法. Kruskal算法 每次选取权值最小的边.然后检查是否加入后形成回路,如果形成回路则需要放弃.最终构成最小生成树.n个顶点的图最小生成树步骤如下: 边的权值升序排序: 选取所有未遍历的边中权

贪心算法-最小生成树Kruskal算法和Prim算法

Kruskal算法: 不断地选择未被选中的边中权重最轻且不会形成环的一条. 简单的理解: 不停地循环,每一次都寻找两个顶点,这两个顶点不在同一个真子集里,且边上的权值最小. 把找到的这两个顶点联合起来. 初始时,每个顶点各自属于自己的子集合,共n个子集合. 每一步操作,都会将两个子集合融合成一个,进而减少一个子集合. 结束时,所有的顶点都在同一个子集合里,这个子集合就是最小生成树. 例子: 伪代码: Prim算法: G=(V,E),S是V的真子集,如果u在S中,v在V-S中,且(u,v)是图的一

最小生成树(Prim算法和Kruskal算法)

1)最小生成树 给定一个无向图,如果它的某个子图中任意两个顶点都互相连通并且是一棵树,那么这棵树就叫生成树.如果边上有权值,那么使得边权和最小的生成树叫做最小生成树(MST,Minimum Spanning Tree) 2)应用 比如让你为一个镇的九个村庄架设通信网络,每个村庄相当于一个顶点,权值是村与村之间可通达的直线距离,要求你必须用最小的成本完成这次任务:或者村庄之间建公路,连通N个村庄要N-1条路,如何让建路成本最低之类的问题. 1.Prim算法 ①该算法是构建最小生成树的算法之一.它是

java实现最小生成树的prim算法和kruskal算法

在边赋权图中,权值总和最小的生成树称为最小生成树.构造最小生成树有两种算法,分别是prim算法和kruskal算法.在边赋权图中,如下图所示: 在上述赋权图中,可以看到图的顶点编号和顶点之间邻接边的权值,若要以上图来构建最小生成树.结果应该如下所示: 这样构建的最小生成树的权值总和最小,为17 在构建最小生成树中,一般有两种算法,prim算法和kruskal算法 在prim算法中,通过加入最小邻接边的方法来建立最小生成树算法.首先构造一个零图,在选一个初始顶点加入到新集合中,然后分别在原先的顶点

最小生成树之 prim算法和kruskal算法(以 hdu 1863为例)

最小生成树的性质 MST性质:设G = (V,E)是连通带权图,U是V的真子集.如果(u,v)∈E,且u∈U,v∈V-U,且在所有这样的边中, (u,v)的权c[u][v]最小,那么一定存在G的一棵最小生成树,(u,v)为其中一条边. 构造最小生成树,要解决以下两个问题: (1).尽可能选取权值小的边,但不能构成回路(也就是环). (2).选取n-1条恰当的边以连接网的n个顶点. Prim算法的思想: 设G = (V,E)是连通带权图,V = {1,2,-,n}.先任选一点(一般选第一个点),首

最小生成树-Prim算法和Kruskal算法

原文链接:http://www.cnblogs.com/biyeymyhjob/archive/2012/07/30/2615542.html Prim算法 1.概览 普里姆算法(Prim算法),图论中的一种算法,可在加权连通图里搜索最小生成树.意即由此算法搜索到的边子集所构成的树中,不但包括了连通图里的所有顶点(英语:Vertex (graph theory)),且其所有边的权值之和亦为最小.该算法于1930年由捷克数学家沃伊捷赫·亚尔尼克(英语:Vojtěch Jarník)发现:并在195

最小生成树:prim算法和kruskal算法

一个连通图的生成树是图的极小连通子图.它包含图中的所有顶点,并且只含尽可能少的边.若砍去它的一条边,就会使生成树变成非连通图:若给它增加一条边,则会形成一条回路. 最小生成树有如下性质: 1.最小生成树非唯一,可能有多个最小生成树: 2.最小生成树的边的权值之和总唯一,而且是最小的: 3.最小生成树的边数为顶点数减1. 构造最小生成树可以有多种算法.其中多数算法利用了最小生成树的下列一种简称为MST的性质: 假设N=(V,{E})是一个连通网,U是顶点集V的一个非空子集.若(u, v)是一条具有

转载:最小生成树-Prim算法和Kruskal算法

本文摘自:http://www.cnblogs.com/biyeymyhjob/archive/2012/07/30/2615542.html 最小生成树-Prim算法和Kruskal算法 Prim算法 1.概览 普里姆算法(Prim算法),图论中的一种算法,可在加权连通图里搜索最小生成树.意即由此算法搜索到的边子集所构成的树中,不但包括了连通图里的所有顶点(英语:Vertex (graph theory)),且其所有边的权值之和亦为最小.该算法于1930年由捷克数学家沃伊捷赫·亚尔尼克(英语: