对于上面的图,我们对边进行排序,取前4条边就是一个最小生成树,这样的话,看起来似乎我们只需要对边进行排序,直到点的数量等于边的数量+1(所有的点已经有啦,再加就不是最小生成树了)。
但是我们将第三条边和第8条边换一下,即A-D的权值为2,C-E的权值为8,那么之前的想法还对吗?,这时候当选A-D时就会形成回路了,即不是最小生成树了。那么我们是不是还要加条件呢,对了,我们还要加上并查集,我们将已经在生成树中的顶点存为一个集合,查询加入的边的两点是否和之前的顶点属于同一集合,若是不属于则加入,那么这就是krusual算法了。
代码如下:
package _图;
import java.util.Arrays;
import java.util.Scanner;
public class _Kruskal {
static int[] par = new int[100];
static int[] rank = new int[100];
// 并查集初始化
static void init(int n) {
for (int i = 0; i < n; i++) {
par[i] = i;
rank[i] = 0;
}
}
// 并查集查找
static int find(int x) {
if (par[x] == x)
return x;
else
return par[x] = find(par[x]);
}
//合并集合
static void unite(int x,int y) {
x=find(x);
y=find(y);
if(x==y)
return;
else {
if(rank[x]<rank[y]) {
par[x]=y;
}else {
par[y]=x;
if(rank[x]==rank[y])rank[x]++;
}
}
}
//判断是否同一集合
static boolean same(int x,int y) {
return find(x)==find(y);
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc = new Scanner(System.in);
int V=sc.nextInt();
int E = sc.nextInt();
Edge[] es = new Edge[E];
for (int i = 0; i < E; i++)
es[i] = new Edge();
// 输入边
for (int i = 0; i < es.length; i++) {
int u = sc.nextInt();
int v = sc.nextInt();
int w = sc.nextInt();
es[i].u = u;
es[i].v = v;
es[i].w = w;
}
// 边排序
Arrays.sort(es);
//并查集初始化
init(V);
int res=0;
int k=0;
for (int i = 0; i < E; i++) {
Edge e=new Edge();
if(!same(e.u,e.v)) { //两个边不属于一个集合
unite(e.u,e.v);
res+=e.w;
k++;
if(k==n-1)break;//如果顶点已经是n个时,最小生成树已经完成。
}
}
System.out.println(res);
}
}
class Edge implements Comparable<Edge> {
int u, v;
int w;
@Override
public int compareTo(Edge o) {
// TODO Auto-generated method stub
if (w < o.w)
return -1;
else
return 1;
}
}