1584.连接所有点的最小费用(最小生成树&并查集union find)

链接:1584. 连接所有点的最小费用 - 力扣(LeetCode)

题解:

1.求得所有边的距离

2.贪心:按照边距离最小的排序

3.遍历所有边,

如果边的两个点没有联通,则增加边。

如果连通过则不放入

记录连接边数量,如果边数量为节点数量-1,则停止

cpp 复制代码
class UnionFind {
public:
    bool is_connected(int a, int b) {
        int fa = get_father(a);
        int fb = get_father(b);
        if (fa == fb) {
            return true;
        }
        return false;
    }
    void merge(int a, int b) {
        int fa = get_father(a);
        int fb = get_father(b);
        _father[fa] = fb;
    }
    int get_father(int a) {
        while (_father[a] != a) {
            a = _father[a];
        }
        return a;
    }
    void add(int a) {
        if (_father.find(a) == _father.end()) {
            _father[a] = a;
        }
    }
    unordered_map<int, int> _father;
};
class Solution {
public:
    struct Edge {
        int a;
        int b;
        int cost;
        Edge(int x, int y, int c) {
            a = x;
            b = y;
            cost = c;
        }
    };
    int dist(int x1, int y1, int x2, int y2) {
        return abs(x1 - x2) + abs(y1 - y2);
    }
    int minCostConnectPoints(vector<vector<int>>& points) {
        int len = points.size();
        if (len <= 0) {
            return 0;
        }
        UnionFind uf;
        vector<Edge> edges;
        for (int i = 0; i < len; ++i) {
            uf.add(i);
            for (int j = i + 1; j < len; ++j) {
                edges.push_back(Edge(i, j,
                                dist(points[i][0], points[i][1], points[j][0],
                                     points[j][1])));
            }
        }
        sort(edges.begin(), edges.end(),
             [](Edge& e1, Edge& e2) { return e1.cost < e2.cost; });
        int result = 0;
        int count = 0;
        for (auto& e : edges) {
            if (count == points.size() - 1) {
                break;
            }
            if (uf.is_connected(e.a, e.b)) {
                continue;
            }
            uf.merge(e.a, e.b);
            result += e.cost;
            ++count;
        }
        return result;
    }
};

深入解析:Leetcode 最小生成树系列(1) - yjbjingcha - 博客园

cpp 复制代码
## Kruskal 算法

```java
/**
 * Definition for a Connection.
 * public class Connection {
 *   public String city1, city2;
 *   public int cost;
 *   public Connection(String city1, String city2, int cost) {
 *       this.city1 = city1;
 *       this.city2 = city2;
 *       this.cost = cost;
 *   }
 * }
 */

public class Solution {

    public List<Connection> lowestCost(List<Connection> connections) {
        UnionFind uf = new UnionFind();
        for (Connection connection : connections) {
            uf.add(connection.city1);
            uf.add(connection.city2);
        }
        int n = uf.father.size();
        int m = connections.size();
        Collections.sort(connections, new Comparator<Connection>() {
            public int compare(Connection a, Connection b) {
                if (a.cost != b.cost) {
                    return a.cost - b.cost;
                }
                if (!a.city1.equals(b.city1)) {
                    return a.city1.compareTo(b.city1);
                }
                return a.city2.compareTo(b.city2);
            }
        });
        
        int edges = 0;
        List<Connection> MST = new LinkedList<>();
        for (Connection connection : connections) {
            if (edges == n - 1) {
                break;
            }
            if (!uf.isConnected(connection.city1, connection.city2)) {
                uf.merge(connection.city1, connection.city2);
                MST.add(connection);
                edges += 1;
            }
        }
        if (edges != n - 1) {
            return new LinkedList<>();
        }
        
        return MST;
    }
}

class UnionFind {
    public Map<String, String> father;
    private Map<String, Integer> sizeOfSet;
    private int numOfSet = 0;
    public UnionFind() {
        father = new HashMap<String, String>();
        sizeOfSet = new HashMap<String, Integer>();
        numOfSet = 0;
    }
    
    public void merge(String x, String y) {
        String rootX = find(x);
        String rootY = find(y);
        if (!rootX.equals(rootY)) {
            father.put(rootX, rootY);
            numOfSet--;
            sizeOfSet.put(rootY, sizeOfSet.get(rootX) + sizeOfSet.get(rootY));
        }
    }
    
    public String find(String x) {
        String root = x;
        while (father.get(root) != null) {
            root = father.get(root);
        }

        while (!x.equals(root)) {
            String originalFather = father.get(x);
            father.put(x, root);
            x = originalFather;
        }
        
        return root;
    }
    
    public void add(String x) {
        if (father.containsKey(x)) {
            return;
        }
        father.put(x, null);
        sizeOfSet.put(x, 1);
        numOfSet++;
    }
    
    public boolean isConnected(String x, String y) {
        return find(x).equals(find(y));
    }
    
    public int getNumOfSet() {
        return numOfSet;
    }
    
    public int getSizeOfSet(String x) {
        return sizeOfSet.get(find(x));
    }
    
}
```

``` python
'''
Definition for a Connection
class Connection:

    def __init__(self, city1, city2, cost):
        self.city1, self.city2, self.cost = city1, city2, cost
'''

class Solution:
    
    def lowestCost(self, connections):
        import functools
        
        uf = UnionFind();
        for connection in connections:
            uf.add(connection.city1)
            uf.add(connection.city2)
        
        n, m = len(uf.father), len(connections)
        connections.sort(key = functools.cmp_to_key(self.cmp))
        
        edges, MST = 0, []
        for connection in connections:
            if edges == n - 1:
                break
            if not uf.is_connected(connection.city1, connection.city2):
                uf.merge(connection.city1, connection.city2)
                MST.append(connection)
                edges += 1
        if edges != n - 1:
            return []
        return MST
    
    def cmp(self, a, b):
        if a.cost != b.cost:
            if a.cost > b.cost:
                return 1
            return -1
        if a.city1 != b.city1:
            if a.city1 > b.city1:
                return 1
            return -1
        if a.city2 != b.city2:
            if a.city2 > b.city2:
                return 1
            return -1
        return 0
    
    
class UnionFind:

    def __init__(self):
        self.father = {}
        self.size_of_set = {}
        self.num_of_set = 0

    def merge(self, x, y):
        root_x, root_y = self.find(x), self.find(y)
        if root_x != root_y:
            self.father[root_x] = root_y
            self.num_of_set -= 1
            self.size_of_set[root_y] += self.size_of_set[root_x]

    def find(self, x):
        root = x
        while self.father[root] != None:
            root = self.father[root]
        while x != root:
            original_father = self.father[x]
            self.father[x] = root
            x = original_father
        return root

    def add(self, x):
        if x in self.father:
            return
        self.father[x] = None
        self.num_of_set += 1
        self.size_of_set[x] = 1
    
    def is_connected(self, x, y):
        return self.find(x) == self.find(y)
    
    def get_num_of_set(self):
        return self.num_of_set
    
    def get_size_of_set(self, x):
        return self.size_of_set[self.find(x)]

```



## Prim 算法

```java
/**
 * Definition for a Connection.
 * public class Connection {
 *   public String city1, city2;
 *   public int cost;
 *   public Connection(String city1, String city2, int cost) {
 *       this.city1 = city1;
 *       this.city2 = city2;
 *       this.cost = cost;
 *   }
 * }
 */

public class Solution {

    public List<Connection> lowestCost(List<Connection> connections) {
        Map<String, Integer> nameToId = new HashMap<>();
        Map<Integer, String> idToName = new HashMap<>();
        for (Connection connection : connections) {
            if (!nameToId.containsKey(connection.city1)) {
                nameToId.put(connection.city1, nameToId.size());
                idToName.put(idToName.size(), connection.city1);
            }
            if (!nameToId.containsKey(connection.city2)) {
                nameToId.put(connection.city2, nameToId.size());
                idToName.put(idToName.size(), connection.city2);
            }
        }
        int n = nameToId.size();
        int[][] edges = new int[n][n];
        int[][] graph = new int[n][n];
        for (int i = 0; i < n; i++) {
            Arrays.fill(graph[i], Integer.MAX_VALUE);
            Arrays.fill(edges[i], Integer.MAX_VALUE);
        }
        for (Connection connection : connections) {
            int start = nameToId.get(connection.city1);
            int end = nameToId.get(connection.city2);
            graph[start][end] = Math.min(graph[start][end], connection.cost);
            graph[end][start] = Math.min(graph[end][start], connection.cost);
            edges[start][end] = Math.min(edges[start][end], connection.cost);
        }
        
        List<Connection> MST = new LinkedList<>();
        int[][] minDistance = new int[n][2];
        Set<Integer> visited = new HashSet<>();
        visited.add(0);
        for (int i = 1; i < n; i++) {
            minDistance[i][0] = graph[0][i];
            minDistance[i][1] = 0;
        }
        
        for (int i = 1; i < n; i++) {
            int cost = Integer.MAX_VALUE;
            int nextNode = -1;
            for (int j = 0; j < n; j++) {
                if (!visited.contains(j) && cost > minDistance[j][0]) {
                    nextNode = j;
                    cost = minDistance[j][0];
                }
            }
            if (cost == Integer.MAX_VALUE) {
                return new LinkedList<>();
            }
            
            visited.add(nextNode);
            int start = minDistance[nextNode][1];
            int end = nextNode;
            if (edges[start][end] != Integer.MAX_VALUE && edges[start][end] < edges[end][start]) {
                MST.add(new Connection(idToName.get(start), idToName.get(end), cost));
            }
            if (edges[end][start] != Integer.MAX_VALUE && edges[end][start] < edges[start][end]) {
                MST.add(new Connection(idToName.get(end), idToName.get(start), cost));
            }

            for (int j = 0; j < n; j++) {
                if (!visited.contains(j) && minDistance[j][0] > graph[nextNode][j]) {
                    minDistance[j][0] = graph[nextNode][j];
                    minDistance[j][1] = nextNode;
                }
            }
        }
        
        Collections.sort(MST, new Comparator<Connection>() {
            public int compare(Connection a, Connection b) {
                if (a.cost != b.cost) {
                    return a.cost - b.cost;
                }
                if (!a.city1.equals(b.city1)) {
                    return a.city1.compareTo(b.city1);
                }
                return a.city2.compareTo(b.city2);
            }
        });
        
        return MST;
    }
}

```

``` python
'''
Definition for a Connection
class Connection:

    def __init__(self, city1, city2, cost):
        self.city1, self.city2, self.cost = city1, city2, cost
'''
class Solution:

    def cmp(self, a, b):
        if a.cost != b.cost:
            if a.cost > b.cost:
                return 1
            return -1
        if a.city1 != b.city1:
            if a.city1 > b.city1:
                return 1
            return -1
        if a.city2 != b.city2:
            if a.city2 > b.city2:
                return 1
            return -1
        return 0

    def lowestCost(self, connections):
        import functools
        
        name_to_id, id_to_name = {}, {}
        for connection in connections:
            if connection.city1 not in name_to_id:
                name_to_id[connection.city1] = len(name_to_id)
                id_to_name[len(id_to_name)] = connection.city1
            if connection.city2 not in name_to_id:
                name_to_id[connection.city2] = len(name_to_id)
                id_to_name[len(id_to_name)] = connection.city2

        n = len(name_to_id)
        graph = [[float("inf")] * n for _ in range(n)]
        edges = [[float("inf")] * n for _ in range(n)]
        for connection in connections:
            start = name_to_id[connection.city1]
            end = name_to_id[connection.city2]
            graph[start][end] = min(graph[start][end], connection.cost)
            graph[end][start] = min(graph[end][start], connection.cost)
            edges[start][end] = min(edges[start][end], connection.cost)

        mst, min_distance = [], [(0, 0)] * n
        visited = set([0])
        for i in range(1, n):
            min_distance[i] = (graph[0][i], 0)
        
        for i in range(1, n):
            cost, next_node = float("inf"), -1
            for j in range(n):
                if j not in visited and cost > min_distance[j][0]:
                    next_node = j
                    cost = min_distance[j][0]
            if cost == float("inf"):
                return []
            
            visited.add(next_node)
            start, end = min_distance[next_node][1], next_node
            if edges[start][end] != float("inf") and edges[start][end] < edges[end][start]:
                mst.append(Connection(id_to_name.get(start), id_to_name.get(end), cost))
            if edges[end][start] != float("inf") and edges[end][start] < edges[start][end]:
                mst.append(Connection(id_to_name.get(end), id_to_name.get(start), cost))
                
            for j in range(n):
                if j not in visited and min_distance[j][0] > graph[next_node][j]:
                    min_distance[j] = (graph[next_node][j], next_node)
        
        mst.sort(key = functools.cmp_to_key(self.cmp))
        return mst
        
```
相关推荐
wabs6661 小时前
关于二叉树【力扣144.二叉树的前序遍历的思考】
数据结构·c++·算法·leetcode·二叉树
zmzb01031 小时前
C++课后习题训练记录Day199
开发语言·c++
人邮异步社区1 小时前
如何系统地学习 C++ 语言?
开发语言·c++·学习
欧特克_Glodon1 小时前
OpenCV计算机视觉开发入门与实践<二十>:非线性变换灰度变换
c++·人工智能·opencv·计算机视觉
1000世界小札7 小时前
《大话数据结构》第9章精读:归并排序与快速排序完整 C++ 实现
数据结构·c++·算法
2601_9561219710 小时前
背包基础篇(01、完全、分组、多重、混合)
c++·算法·动态规划
fpcc10 小时前
跟我学C++中级篇——编译期的条件选择
开发语言·c++
ShineWinsu15 小时前
对于C++:C++20中线程、初始化、Lambda与内存视图等特性的解析
c++·c++20
Xin77015 小时前
LeetCode 23.合并 K 个升序链表(分治递归)
leetcode