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;
    }
}