最低成本联通所有城市【kruskal】【prim】

Kruskal

思路

贪心思想,将所有边进行排序,依次连接。利用UF判断亮点连通性,若2点已经连通,则跳过,避免成环。

实现

class Solution {
    public int minimumCost(int n, int[][] connections) {
        int cost = 0;
        Arrays.sort(connections, (x, y) -> x[2] - y[2]);
        UF uf = new UF(n);
        for (int[] connection: connections) {
            if (uf.conntected(connection[0] - 1, connection[1] - 1))
                continue;
            cost += connection[2];
            uf.union(connection[0] - 1, connection[1] - 1);
        }
        return uf.count() == 1? cost: -1;
    }
}

class UF {
    private int count;

    private int[] parent;

    public UF(int n) {
        count = n;
        parent = new int[n];
        for (int i = 0; i < n; i++)
            parent[i] = i;
    }

    public void union(int p, int q) {
        int rootP = find(p);
        int rootQ = find(q);
        if (rootP == rootQ) return;
        parent[rootP] = rootQ;
        count--;
    }
    
    public boolean conntected(int p, int q) {
        return find(p) == find(q);
    }

    public int find(int x) {
        if (parent[x] != x) {
            parent[x] = find(parent[x]);
        }
        return parent[x];
    }

    public int count() {
        return count;
    }
}

Prim

思路

每次将一个图切成2个连通分量,那么总有一条边是最小生成树的边。找到其中最小的边,加入即可。同时,将此边对应的新加入节点的边都加入候选。
为了避免成环,需要一个visited数组记录所有点的访问情况,若已访问则跳过。

实现

class Solution {
    public int minimumCost(int n, int[][] connections) {
        List<int[]>[] graph = buildGraph(n, connections);
        Prim prim = new Prim(graph);
        return prim.isAllConnected()? prim.minSum(): -1;
    }

    public List<int[]>[] buildGraph(int n, int[][] connections) {
        List<int[]>[] graph = new LinkedList[n];
        for (int i = 0; i < n; i++)
            graph[i] = new LinkedList<>();
        for (int[] connection: connections) {
            int from = connection[0] - 1;
            int to = connection[1] - 1;
            int cost = connection[2];
            graph[from].add(new int[]{from, to, cost});
            graph[to].add(new int[]{to, from, cost});
        }
        return graph;
    }
}


class Prim {
    private PriorityQueue<int[]> pq;

    private boolean[] inMST;

    private int minSum = 0;

    private List<int[]>[] graph;

    public Prim(List<int[]>[] graph) {
        this.graph = graph;
        inMST = new boolean[graph.length];
        pq = new PriorityQueue<>((x, y) -> x[2] - y[2]);
        inMST[0] = true;
        cut(0);
        while (!pq.isEmpty()) {
            int[] edeg = pq.poll();
            int to = edeg[1];
            int weight = edeg[2];
            if (inMST[to]) continue;
            minSum += weight;
            inMST[to] = true;
            cut(to);
        }
    }

    public void cut(int n) {
        for (int[] edeg: graph[n]) {
            int to = edeg[1];
            if (inMST[to]) continue;
            pq.offer(edeg);
        }
    }

    public int minSum() {
        return minSum;
    }

    public boolean isAllConnected() {
        for (boolean visited: inMST) {
            if (!visited) return false;
        }
        return true;
    }
}
posted @ 2023-08-28 15:58  kiper  阅读(13)  评论(0编辑  收藏  举报