连接所有点的最小费用
- 来源 : LeetCode - 连接所有点的最小费用
- 难度 : 中等
- 标签 : 最小生成树
题目描述
-
给你一个points数组,表示2D平面上的一些点,其中points[i]为第i个点。
-
连接点[xi, yi]和点 [xj, yj]的费用为它们之间的 曼哈顿距离 : |xi - xj| + |yi - yj| ,其中 |val| 表示 val的绝对值。
-
请你返回将所有点连接的最小总费用。只有任意两点之间有且仅有一条简单路径时,才认为所有点都已连接。
=>
解法构思
结合图论或数据结构的有关知识,显然可以想到是最小生成树问题,不妨采用Prim算法
Prim算法介绍 :
Prim算法寻找最小生成树的思路是假想有两个集合,一个为已经参与建树的点集,一个为未参与建树的点集,每次都从已建树点集中的点到为建树点集中的点的所有边中选择权重最小的一个,这条边就加入构建生成树,相应的,这条边的终点就从未建树点集移到另一集合中, 如此反复直到所有点都参与建树则停止, 在进行过程中, 记录生成树的有关信息, 对于此题仅需要将每次选出的最小边的权重累加, 最后得到此题结果。
- 为了提高效率, 利用一表记录每个未建树点形成的最小权值(每个未建树点, 其到每个已建树点有边, 记录其中最小者, 每个未建树点都有这么一条记录), 每当生成树增加一个点时, 更新此表。
上手编程
// 曼哈顿距离
#define PRICE(p1, p2) ( abs( (p1)[0] - (p2)[0] ) + abs( (p1)[1] - (p2)[1] ) )
int minCostConnectPoints(vector<vector<int>>& points) {
const int N = points.size();
int res = 0; // 结果
vector<vector<int>> W(N, vector<int>(N, 0)) // 邻接矩阵;
vector<int> lowCost(N, 0); // 最小权值表
vector<char> okSet(N, 0); // 记录每个点是否已建树, 是为1, 否为0
// 建立邻接矩阵
for (int i = 0; i < N; ++i)
for (int j = i + 1; j < N; ++j)
W[i][j] = W[j][i] = PRICE(points[i], points[j]);
// 从0号点开始建树
okSet[0] = true;
// 初始化 / 构建此时的最小权值表
for (int i = 1; i < N; ++i)
lowCost[i] = W[0][i];
// 一共需要再找出N-1个点建树
for (int cnt = 1; cnt < N; ++cnt) {
// 此次选出的最小权值, 及对应的出发点的序号(此点即即将参与建树的点)
int min_price = INT_MAX, min_targetIndex = 0;
// 找连接两个集合点的最小权值的边
for (int i = 0; i < N; ++i) {
if (!okSet[i]) { // 仅处理 从未建树点出发的边
if (lowCost[i] < min_price) {
min_price = lowCost[i];
min_targetIndex = i;
}
}
}
// 累计最小权值
res += min_price;
// 建树点集中加入刚选出的点
okSet[min_targetIndex] = true;
// 更新lowCost表
for (int i = 0; i < N; ++i)
if (!okSet[i]) lowCost[i] = min(lowCost[i], W[i][min_targetIndex]);
}
return res;
}