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
//常规prim是针对点来遍历,时间复杂度高,可以将边存储,
//首先将边按照权值将边从小到大排序
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]);
}
//新建一个集合存储点,为了方便终止遍历,使用hashset
HashSet<Integer> vers = new HashSet<>();
vers.add(edges.get(0)[0]);
vers.add(edges.get(0)[1]);
int sum = edges.get(0)[2];
//新建一个集合用来剪枝,删除不会再用的边
ArrayList<Integer> delete = new ArrayList<>();
while (vers.size()<n){
for (int i = 0; i < edges.size(); i++) {
if(vers.contains(edges.get(i)[0]) && vers.contains(edges.get(i)[1])){
//如果这条边的两个点都到访过了,那以后也就不用了
delete.add(i);
} else if (!vers.contains(edges.get(i)[0]) && !vers.contains(edges.get(i)[1])) {
//啥也不做,纯粹是不想写太长的条件,排除掉这个边的两点都没访问过的情况
} else{
//因为边集合已经排过序,所以遇到的第一个符合要求的就是最短的,将其设为访问,然后跳出这次循环
vers.add(edges.get(i)[0]);
vers.add(edges.get(i)[1]);
sum += edges.get(i)[2];
delete.add(i);
break;
}
}
//将不用的边删除
for (int i = delete.size()-1; i >= 0; i--) {
edges.remove(delete.get(i).intValue());
}
delete.clear();
}
return sum;
}
}