村庄分水最优分配(上)| 8月更文挑战

278 阅读2分钟

问题假设

假如一个村庄有 n 个房子🏡,我们通过建造水井和管道来为所有房屋供水。

对每个房屋 i 来说,我们既可以在其内部建造水井,花费的钱用 wells[i-1] 表示,也可以通过管道来获得其他水井的水。两个房屋间的管道修建费使用数组 pipes 表示,对于每个 pipes[j] = [house1j, house2j, costj] 代表使用管道连接房屋 house1j 和 house2j 的费用。连接是双向的。

要计算能给所有房屋供水的最小建造费用。

比如下图,n = 3, wells = [1, 2, 2], pipes = [[1, 2, 1], [2, 3, 1]]

最优策略是在第一幢房子修建水井,花费1,然后通过管道连接将水提供给其他房屋,花费2,总花费为3。

image.png

问题分析

据问题描述涉及到房屋(顶点)通过管道(边)进行连接,我们可以看出这个问题是图问题的一种变体。更准确地说,我们可以将其转化为最小生成树问题。

关于最小生成树问题,有两种经典解法—— Prim 算法和 Kruskal 算法,这二者都是面试中最受欢迎且被认可的算法。

首先,介绍一下最小生成树算法。

给定一个连通的,边加权的无向图,最小生成树是连接所有顶点的边的子集,这些边的总权重在所有可能中是最小的。

我们可以把此问题的房屋考虑成图中的顶点,房屋之间的管道理解为图中的边。

然而,其中有一个主要的区别是。此问题中每个顶点和每条边都计算开销,而在最小生成树中只有边计算开销。

为了抹平这个差异,可以为图添加一个虚拟顶点,并且添加虚拟顶点和其他顶点之间的边,然后将每个顶点的开销重新分配给新添加的边。

image.png

通过以上转换,我们可以将顶点的开销转移到新增的边上。于是我们的问题简化为通过一个有权边列表创建最小生成树的问题。

image.png

通过上图,我们可以根据最小生成树的结果得出该问题的解法是在索引为1处的房子建造水井,然后通过管道为其他房屋供水。