1584. 連接所有點的最小費用

中等 並查集 最小生成樹

前置題目:P3366 最小生成樹

思路

題目要找到連接所有點的最小費用。
任意兩點都要滿足「有且僅有」一條簡單路徑。
更精確來說,每個點之間都要有辦法抵達任意其他點,而路徑不一定要一步到位。
而最小生成樹就滿足這個條件,只要對模板稍做修改,就滿足條件了。

程式碼

1. 最小生成樹 Kruskal

struct Edge {
    int u, v, w;
    Edge(int u, int v, int w) : u(u), v(v), w(w) {}
    bool operator<(const Edge& other) const {
        return this->w < other.w;
    }
};
class Solution {
private:
    static const int MX = 1001;
    int parent[MX];
    int setSize[MX];
    void build(int n) {
        iota(parent, parent + n, 0);
        fill(setSize, setSize + n, 1);
    }
    int find(int x) {
        if(parent[x] != x) {
            parent[x] = find(parent[x]);
        }
        return parent[x];
    }
    bool isSameSet(int u, int v) {
        return find(u) == find(v);
    }
    void unite(int x, int y) {
        parent[find(x)] = parent[find(y)];
    }
public:
    int minCostConnectPoints(vector<vector<int>>& points) {
        int n = points.size();
        build(n);
        vector<Edge> edges;
        for(int i = 0; i < n; i++) {
            for(int j = i + 1; j < n; j++) {
                int dist = abs(points[i][0] - points[j][0]) + 
                           abs(points[i][1] - points[j][1]);
                edges.push_back(Edge(i, j, dist));
            }
        }
        sort(edges.begin(), edges.end());
        int edgeCnt = 0;
        int cost = 0;
        for(auto& edge : edges) {
            if(!isSameSet(edge.u, edge.v)) {
                unite(edge.u, edge.v);
                cost += edge.w;
                if(++edgeCnt == n - 1) {
                    break;
                }
            }
        }
        return cost;
    }
};

2. 最小生成樹 Prim

class Solution {
public:
    int minCostConnectPoints(vector<vector<int>>& points) {
        using pii = pair<int,int>;
        int n = points.size();
        vector<vector<pii>> graph(n);
        for(int i = 0; i < n; i++) {
            for(int j = i + 1; j < n; j++) {
                // i -> j, 花費曼哈頓距離   
                int dist = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1]);
                graph[i].push_back({dist, j});
                graph[j].push_back({dist, i});
            }
        }
        priority_queue<pii, vector<pii>, greater<pii>> pq; // 記錄權重,鄰居
        vector<bool> used(n, false);
        used[0] = true;
        int nodeCnt = 1;
        int res = 0;
        for(pii neighbor : graph[0]) {
            pq.push(neighbor);
        }
        while(!pq.empty()) {
            auto [dist, v] = pq.top(); pq.pop();
            if(!used[v]) {
                used[v] = true;
                res += dist;
                if(++nodeCnt == n) {
                    break;
                }
                for(pii neighbor : graph[v]) {
                    pq.push(neighbor); 
                }
            }
        }
        return res;
    }
};

複雜度分析

  • 時間複雜度:O(mlogm)O(m\log{m})
  • 空間複雜度:O(n+m)O(n+m)

顯示設定

背景線條
顯示背景網格線條
懸停發光
滑鼠懸停時顯示霓虹效果
聚光燈
跟隨滑鼠的聚光燈效果
背景透明度
開啟透明玻璃效果
主題顏色
自訂主要顏色