import java.util.*; public class Solution { /** * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可 * * 返回最小的花费代价使得这n户人家连接起来 * @param n int n户人家的村庄 * @param m int m条路 * @param cost int二维数组 一维3个参数,表示连接1个村庄到另外1个村庄的花费的代价 * @return int */ public int miniSpanningTree (int n, int m, int[][] cost) { // write code here //这次用kruskal算法做 //思路:找到最短的边,然后找次短的边, //用并查集的思想判断这个边和它的终点是否相同, //若相同,就不要, //若不同,就加入集合, //直到找到n-1条边 int sum = 0; Arrays.sort(cost, Comparator.comparingInt(o -> o[2])); //新建一个ArrayList存储边,以便于遍历时将不会用到的边删除,即剪枝。 ArrayList<int[]> edges = new ArrayList<>(); for (int i = 0; i < m; i++) { edges.add(cost[i]); } sum += edges.get(0)[2]; //建立一个数组用来实现并查集,初始时,每个点的终点是他本身 int[] ends = new int[n+1]; for (int i = 0; i < n+1; i++) { ends[i] = i; } //将最短边的两点终点设为同一个点 int start = edges.get(0)[0]; ends[start] = edges.get(0)[1]; int index = 1; int a; int b; //新建一个集合用来剪枝,删除不会再用的边 ArrayList<Integer> delete = new ArrayList<>(); while (index < n-1){ for (int i = 0; i < m; i++) { a = edges.get(i)[0]; b = edges.get(i)[1]; if(findEnd(ends,a)!=findEnd(ends,b)){ //将终点合一 ends[findEnd(ends,a)] = ends[b]; sum += edges.get(i)[2]; break; }else { delete.add(i); } } index++; //将不用的边删除 for (int i = delete.size() - 1; i >= 0; i--) { edges.remove(delete.get(i).intValue()); } delete.clear(); } return sum; } public int findEnd(int[] ends, int i){ while (ends[i]!=i){ i = ends[i]; } return i; } }