並查集之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. 默認每個數都不在新集合中, 計算沒有在新集合中點的距離(當前集合中的個數大於1[新集合]就不就計算了距離,留第二個步驟中計算)
  2. 在第一步中多組集合,現在就需要計算集合與集合之間的關係,求得集合與集合的最小距離就要合併新的集合中去, 依次計算出每個集合與集合之間的最小距離。

舉例:

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()

總結

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章