DAY56

73 阅读1分钟

1135 Connecting Cities With Minimum Cost

There are n cities labeled from 1 to n. You are given the integer n and an array connections where connections[i] = [xi, yi, costi] indicates that the cost of connecting city xi and city yi (bidirectional connection) is costi.

Return the minimum cost to connect all the n cities such that there is at least one path between each pair of cities. If it is impossible to connect all the n cities, return -1,

The cost is the sum of the connections' costs used.

class Prim {
    constructor(graph) {
        this.graph = graph;
        this.weightSum = 0;
        // 优先队列,按照边的权重从小到大排序
        this.pq = new MinPriorityQueue();
        // 图中有 n 个节点
        const n = graph.length;
        // 布尔数组 inMST 辅助,防止重复计算横切边
        this.inMST = new Array(n).fill(false);

        // 从任意一点开始切分,我们从节点 0 开始
        this.inMST[0] = true;
        this.cut(0);

        // 不断进行切分,向最小生成树中添加边
        while (!this.pq.isEmpty()) {
            const edge = this.pq.dequeue();
            const to = edge.element[1];
            const weight = edge.element[2];
            if (this.inMST[to]) {
                continue;
            }
            // 将边 edge 加入最小生成树
            this.weightSum += weight;
            this.inMST[to] = true;
            // 新加入的节点 to 进行切分,产生更多横切边
            this.cut(to);
        }
    }

    /**
     * 将 s 的横切边加入优先队列
     * @param {number} s - 节点编号
     */
    cut(s) {
        // 遍历 s 的所有邻边
        for (const edge of this.graph[s]) {
            const to = edge[1];
            if (this.inMST[to]) continue;
            // 将边加入优先队列
            this.pq.enqueue(edge, edge[2]);
        }
    }

    /**
     * 获取最小生成树的权重和
     * @returns {number}
     */
    getWeightSum() {
        return this.weightSum;
    }

    /**
     * 判断最小生成树是否包含图中的所有节点
     * @returns {boolean}
     */
    allConnected() {
        return this.inMST.every(inTree => inTree);
    }
}

/**
 * @param {number} n
 * @param {number[][]} connections
 * @return {number}
 */
var minimumCost = function(n, connections) {
    function buildGraph(n, connections) {
        const graph = Array.from({ length: n }, () => []);
        for (const [u, v, weight] of connections) {
            graph[u - 1].push([u - 1, v - 1, weight]);
            graph[v - 1].push([v - 1, u - 1, weight]);
        }
        return graph;
    }

    const graph = buildGraph(n, connections);
    const prim = new Prim(graph);

    if (!prim.allConnected()) {
        return -1;
    }
    return prim.getWeightSum();
};