1168. 水资源分配优化
题目地址(1168. 水资源分配优化)
https://leetcode.com/problems/optimize-water-distribution-in-a-village/
题目描述
村庄内有n户人家,我们可以通过挖井或者建造水管向每家供水。
对于每户人家i,我们可以通过花费 wells[i] 直接在其房内挖水井,或者通过水管连接到其他的水井。每两户住户间铺设水管的费用通过 pipes 数组表示。 pipes[i] = [house1, house2, cost] 表示住户1到住户2间铺设水管的费用为cost。
请求出所有住户都能通水的最小花费。
示例1:
输入: n = 3, wells = [1,2,2], pipes = [[1,2,1],[2,3,1]]
输出: 3
解释:
The image shows the costs of connecting houses using pipes.
The best strategy is to build a well in the first house with cost 1 and connect the other houses to it with cost 2 so the total cost is 3.
提示:
1 <= n <= 10000
wells.length == n
0 <= wells[i] <= 10^5
1 <= pipes.length <= 10000
1 <= pipes[i][0], pipes[i][1] <= n
0 <= pipes[i][2] <= 10^5
pipes[i][0] != pipes[i][1]前置知识
图
最小生成树
公司
暂无
思路

题意,在每个城市打井需要一定的花费,也可以用其他城市的井水,城市之间建立连接管道需要一定的花费,怎么样安排可以花费最少的前灌溉所有城市。
这是一道连通所有点的最短路径/最小生成树问题,把城市看成图中的点,管道连接城市看成是连接两个点之间的边。这里打井的花费是直接在点上,而且并不是所有 点之间都有边连接,为了方便,我们可以假想一个点(root)0,这里自身点的花费可以与 0 连接,花费可以是 0-i 之间的花费。这样我们就可以构建一个连通图包含所有的点和边。 那在一个连通图中求最短路径/最小生成树的问题.
参考延伸阅读中,维基百科针对这类题给出的几种解法。
解题步骤:
创建
POJO EdgeCost(node1, node2, cost) - 节点1 和 节点2 连接边的花费。假想一个
root点0,构建图连通所有节点和
0,[0,i] - i 是节点 [1,n],0-1是节点0和1的边,边的值是节点i上打井的花费wells[i];把打井花费和城市连接点转换成图的节点和边。
对图的边的值排序(从小到大)
遍历图的边,判断两个节点有没有连通 (
Union-Find),已连通就跳过,继续访问下一条边
没有连通,记录花费,连通节点
若所有节点已连通,求得的最小路径即为最小花费,返回
对于每次
union, 节点数n-1, 如果n==0说明所有节点都已连通,可以提前退出,不需要继续访问剩余的边。
这里用加权Union-Find 判断两个节点是否连通,和连通未连通的节点。
举例:n = 5, wells=[1,2,2,3,2], pipes=[[1,2,1],[2,3,1],[4,5,7]]
如图:

从图中可以看到,最后所有的节点都是连通的。
复杂度分析
时间复杂度:
O(ElogE) - E 是图的边的个数空间复杂度:
O(E)
一个图最多有
n(n-1)/2 - n 是图中节点个数条边 (完全连通图)
关键点分析
构建图,得出所有边
对所有边排序
遍历所有的边(从小到大)
对于每条边,检查是否已经连通,若没有连通,加上边上的值,连通两个节点。若已连通,跳过。
代码 (Java/Python3)
Java/Python3)Java code
Pythong3 code
延伸阅读
大家对此有何看法,欢迎给我留言,我有时间都会一一查看回答。更多算法套路可以访问我的 LeetCode 题解仓库:https://github.com/azl397985856/leetcode 。 目前已经 37K star 啦。 大家也可以关注我的公众号《力扣加加》带你啃下算法这块硬骨头。

最后更新于
这有帮助吗?