並查集之1584. 連接所有點的最小費用
前言
一, 1584. 連接所有點的最小費用
給你一個points 數組,表示 2D 平面上的一些點,其中 points[i] = [xi, yi] 。
連接點 [xi, yi] 和點 [xj, yj] 的費用爲它們之間的 曼哈頓距離 :|xi - xj| + |yi - yj| ,其中 |val| 表示 val 的絕對值。
請你返回將所有點連接的最小總費用。只有任意兩點之間 有且僅有 一條簡單路徑時,才認爲所有點都已連接。
示例 1:
輸入:points = [[0,0],[2,2],[3,10],[5,2],[7,0]]
輸出:20
解釋:
我們可以按照上圖所示連接所有點得到最小總費用,總費用爲 20 。
注意到任意兩個點之間只有唯一一條路徑互相到達。
示例 2:
輸入:points = [[3,12],[-2,5],[-4,1]]
輸出:18
示例 3:
輸入:points = [[0,0],[1,1],[1,0],[-1,1]]
輸出:4
示例 4:
輸入:points = [[-1000000,-1000000],[1000000,1000000]]
輸出:4000000
示例 5:
輸入:points = [[0,0]]
輸出:0
提示:
1 <= points.length <= 1000
-106 <= xi, yi <= 106
所有點 (xi, yi) 兩兩不同。
通過次數4,242提交次數8,071
二, 解題思路
根據題意:
集合與集合之間的距離所以並查集建立模型
集合與集合之間的最小距離就需要全部遍歷一次計算出最小的值
一共要分爲兩個步驟來做
- 默認每個數都不在新集合中, 計算沒有在新集合中點的距離(當前集合中的個數大於1[新集合]就不就計算了距離,留第二個步驟中計算)
- 在第一步中多組集合,現在就需要計算集合與集合之間的關係,求得集合與集合的最小距離就要合併新的集合中去, 依次計算出每個集合與集合之間的最小距離。
舉例:
points = [[0,0],[2,2],[3,10],[5,2],[7,0],[5,6]]
第一次合併集合得了
並查集的數據變成了
0, 0, 2 ,0, 0, 2
有兩組集合分別是
集合0
[0,0],[2,2],[5,2],[7,0]
新的集合0中最小距離是11
集合2
[3,10],[5,6]
新的集合2中的最小的距離就是6
第二次合併新的集合
算得新的集合0中點[5,2]到新集合2中的點[5,6]是最小的距離是4
最終的最小是 11 + 6 +4 = 21
流程圖
三, 代碼
class Solution
{
private:
void init(int *union_find, int size)
{
for (int i = 0; i < size; ++i)
{
union_find[i] = i;
}
}
int getfriend(int *union_find, int v)
{
if (union_find[v] == v)
{
return v;
}
return union_find[v] = getfriend(&union_find[0], union_find[v]);
}
public:
int minCostConnectPoints(vector<vector<int>>& points)
{
int ans = 0;
std::map<int, std::vector<int>> union_find_map;
int union_find[points.size()];
init(&union_find[0], points.size());
for (int j = 0; j < points.size(); ++j)
{
int index = -1;//選擇最小那個路徑
int vj = getfriend(&union_find[0], j);
if (vj != j)
{
continue;//說明在集合中需要最後處理集合與集合資金的關係
}
int cost = 10 * 12;
for (int i = 0; i < points.size(); ++i)
{
if (i != j)
{
int vi = getfriend(&union_find[0], i);
if (vi != vj)
{
//計算最小曼哈頓距離
int value = abs(points[i][0]-points[j][0]) + abs(points[i][1]-points[j][1]);
//最小距離
if (value < cost)
{
cost = value;
index = i;
}
}
else
{
printf("error = %d\n", vi);
}
}
}
if (index != -1)
{
ans += cost;
int vi = getfriend(&union_find[0], index);
if(vi != vj)
{
if (vi > vj)
{
union_find[index] = vj;
}
else
{
union_find[j] = vi;
}
}
}
}
printf("ans = %d\n", ans);
for (int i = 0; i < points.size(); ++i)
{
union_find_map[union_find[i]].push_back(i);
}
int hash[union_find_map.size()];
int index = 0;
for (const std::pair<int, std::vector<int>>& _pair: union_find_map)
{
hash[index++] = _pair.first;
}
index = 0;
for (int i = 0; i < union_find_map.size()-1; ++i)
{
int cost = 1000000000;
if (i>= union_find_map.size())
{
continue;
}
for (const int& value1: union_find_map[hash[i]])
{
for (int j = i+1; j < union_find_map.size(); ++j)
{
if (j>= union_find_map.size())
{
continue;
}
for (const int& value2 : union_find_map[hash[j]])
{
int pp = abs(points[value2][0]-points[value1][0]) + abs(points[value2][1]-points[value1][1]);
// printf("i = %d, j = %d, value1 = %d, value2 = %d, pp =%d\n", i, j, value1, value2, pp);
//最小距離
if (pp < cost)
{
cost = pp;
index = j;
}
}
}
}
//合併到新的聚合中去
for (const int & new_value: union_find_map[hash[i]])
{
union_find_map[hash[index]].push_back(new_value);
}
ans = ans + cost;
}
return ans;
}
};
//[[5,8],[18,-6],[-18,13],[-8,-13],[-13,3],[-15,2],[-12,17],[14,16],[-4,3],[-17,-7],[8,9],[17,14],[-13,2],[-3,-1],[4,-20]]
時間複雜度 O ( N 2 + N 2 ) O(N^2+N^2) O(N2+N2)
空間複雜度 O ( ) O() O()