一个有 n 户人家的村庄,有 m 条路相互连接着。村里现在要修路,每条路都有一个成本价格,现在请你帮忙计算下,最少需要花费多少钱,就能让这 n 户人家连接起来。
为一个二维数组,每个元素是一个长度为 3 的一维数组 , 和 表示村庄 和村庄 有一条路,修这条路的成本价格为 。
每户之间可能有多条道路连接,但不可能自己与自己相连。
数据范围: , ,
进阶: 时间复杂度 , 空间复杂度
3,3,[[1,3,3],[1,2,1],[2,3,1]]
2
2,1,[[1,2,1]]
1
/** * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可 * * 返回最小的花费代价使得这n户人家连接起来 * @param n int整型 n户人家的村庄 * @param m int整型 m条路 * @param cost int整型二维数组 一维3个参数,表示连接1个村庄到另外1个村庄的花费的代价 * @param costRowLen int cost数组行数 * @param costColLen int* cost数组列数 * @return int整型 */ int miniSpanningTree(int n, int m, int** cost, int costRowLen, int* costColLen) { // 定义一个数组来存储每个顶点到已加入生成树的最近顶点的距离 int homevexcost[n]; // 定义一个邻接矩阵来存储各顶点之间的边的权重 int edgecost[n][n]; // 初始化最小生成树的总成本为0 int sumcost = 0; int u = 0; int v = 0; int w = 0; // 初始化邻接矩阵中未连接的顶点间的权重为极大值(这里用32767表示) for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { edgecost[i][j] = 32765; } } // 根据给定的边和成本信息填充邻接矩阵 for (int i = 0; i < costRowLen; i++) { u = cost[i][0] - 1; v = cost[i][1] - 1; w = cost[i][2]; edgecost[u][v] = w; edgecost[v][u] = w; // 因为图是无向的 } // 初始化第一个顶点加入生成树的成本为0 homevexcost[0] = 0; // 计算从第一个顶点出发到其他顶点的最短距离 int k = 0; for (int i = 0; i < n; i++) { homevexcost[i] = edgecost[k][i]; } // 主循环来构建最小生成树 for (int i = 1; i < n; i++) { // 寻找离已加入生成树的顶点集合最近的顶点及其成本 int mincost = 32765; int l; for (int j = 0; j < n; j++) { if (homevexcost[j] != 0 && homevexcost[j] < mincost) { mincost = homevexcost[j]; l = j; } } // 更新已加入生成树的顶点集合,并累加当前边的成本到总成本中 k = l; sumcost += mincost; homevexcost[l] = 0; // 更新从新加入的顶点出发到其他顶点的距离 for (int a = 0; a < n; a++) { if (edgecost[k][a] < homevexcost[a]) { homevexcost[a] = edgecost[k][a]; } } } // 返回最小生成树的总成本 return sumcost; }
/** * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可 * * 返回最小的花费代价使得这n户人家连接起来 * @param n int整型 n户人家的村庄 * @param m int整型 m条路 * @param cost int整型二维数组 一维3个参数,表示连接1个村庄到另外1个村庄的花费的代价 * @param costRowLen int cost数组行数 * @param costColLen int* cost数组列数 * @return int整型 */ #include <stdio.h> #include <stdlib.h> #include <string.h> void swap(int* x, int* y) { int z[3] = {0}; memcpy(z, x, 3 * sizeof(int)); memcpy(x, y, 3 * sizeof(int)); memcpy(y, z, 3 * sizeof(int)); } typedef struct _Range { int start, end; } Range; Range new_Range(int s, int e) { Range r; r.start = s; r.end = e; return r; } void quick_sort(int* arr[], const int len) { if (len <= 0) return; //避免len等于负值时错误 //r[]模拟堆疊,p为数量,r[p++]为push,r[--p]为pop且取得元素 Range r[len]; int p = 0; r[p++] = new_Range(0, len - 1); while (p) { Range range = r[--p]; if (range.start >= range.end) continue; int mid = arr[range.end][2]; int left = range.start, right = range.end - 1; while (left < right) { while (arr[left][2] < mid && left < right) left++; while (arr[right][2] >= mid && left < right) right--; if(left<right){ swap(arr[left], arr[right]); //加速设置,使代码尽快遍历完,否则超时 left++; right--; } } if (arr[left][2] > arr[range.end][2]) swap(arr[left], arr[range.end]); else left++; r[p++] = new_Range(range.start, left - 1); r[p++] = new_Range(left + 1, range.end); } } int find(int* parent, int x) { //找到最高的父亲节点 if (parent[x] != x) { parent[x] = find(parent, parent[x]); } return parent[x]; } int miniSpanningTree(int n, int m, int** cost, int costRowLen, int* costColLen ) { // write code here int* parent = (int*)malloc((n+10) * sizeof(int)); for (int i = 1; i <=n; i++) { //初始父亲设置为自己 parent[i] = i; } quick_sort(cost, costRowLen);//按边递增排序 int res = 0; for (int i = 0; i < costRowLen; i++) { //遍历所有边,连通的放入一个并查集 int x = cost[i][0]; int y = cost[i][1]; int z = cost[i][2]; int px = find(parent, x); //查找最上边父亲 int py = find(parent, y); if (px != py) { //如果二者不在同一集合 res += z; parent[px] = py; //设置最上边父亲相同 } } return res; }