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) {
return new Prim2(n,m,cost).miniSpanningTree();
}
}
class Prim2{
static int INF = 0x3f3f3f3f;
int n;
int m;
List<int[]>[]g;
boolean[] vis;
//点 距离
PriorityQueue<int[]> pq = new PriorityQueue<int[]>((o1,o2)-> o1[1] - o2[1]);
Prim2(int n, int m, int [][]cost){
this.n = n;
this.m = m;
g = new List[n+1];
Arrays.setAll(g, l -> new ArrayList());
vis = new boolean[n+1];
for(int[]tuple: cost){
int x = tuple[0], y = tuple[1], w = tuple[2];
g[x].add(new int[]{y,w});
g[y].add(new int[]{x,w});
}
}
public int miniSpanningTree(){
int res = 0, cnt = 0;
pq.add(new int[]{1,0});
while(!pq.isEmpty()){
int []pair = pq.poll();
int x = pair[0], w = pair[1];
if(vis[x]) continue;
vis[x] = true;
cnt++;
res += w;
//松弛邻居
for(int []p: g[x]){
int y = p[0], d = p[1];
if(vis[y])continue;
pq.add(new int[]{y, d});
}
}
System.out.println(cnt == n);
return cnt == n ? res : -1;
}
}
class Prim{
static int INF = 0x3f3f3f3f;
int n;
int [][] g; //邻接矩阵
int []dist; //每个点到当前最小生成树的距离
boolean []vis; //点是否在最小生成树中
Prim(int n, int m, int [][]cost){
this.n = n;
vis = new boolean[n+1];
g = new int [n+1][n+1];
dist = new int[n+1];
Arrays.fill(dist, INF);
for(int[]arr: g) Arrays.fill(arr, INF);
for(int []tuple:cost){
int x = tuple[0], y = tuple[1], d = tuple[2];
g[x][y] = g[x][y];
g[y][x] = g[y][x];
}
}
/**
1.每次选择一个距离最小生成树距离最小的点
2.松弛刚才选择的点邻居
*/
public int miniSpanningTree(){
int res = 0;
dist[1] = 0;//以节点1为最小生成树的起点
for(int i = 0; i < n; i++){
//每次选择距离当前最小生成树最小的边
int t = -1;
for(int j = 1; j <= n; j++){
if(vis[j]) continue;
if(t == -1 || dist[j] < dist[t]) t = j;
}
//不联通
if(i > 0 && (t == -1 || dist[t] == INF)) return -1;
res += dist[t];
vis[t] = true;
//松弛以t为出发点的到期邻居的距离
for(int j = 1; j <= n; j++) if(!vis[j])dist[j] = Math.min(dist[j], g[t][j]);
}
return res;
}
}
class Kruskal{
int n ;
int m;
int[][] edges;
int []p; // 并查集
Kruskal(int n, int m , int [][]cost){
this.n = n;
this.m = m;
p = new int[n+1];
for(int i = 1; i <= n; i++) p[i] = i;
edges = cost;
Arrays.sort(edges, (o1, o2)-> o1[2] - o2[2]);
}
int find(int x){
if(p[x] != x){
p[x] = find(p[x]);
}
return p[x];
}
void merge(int x, int y){
p[x] = y;
}
public int miniSpanningTree(){
int res =0, cnt = 0;
for(int i = 0; i < m; i++){
int x = find(edges[i][0]), y = find(edges[i][1]), w = edges[i][2];
if(x != y){
merge(x,y);
res += w;
cnt++;
}
}
return cnt == n - 1 ? res : -1;
}
}