class Solution:
def minCostToSupplyWater(self, n, wells, pipes):
# Add a virtual node 0, connect it to every house with cost wells[i]
edges = []
for i, cost in enumerate(wells):
edges.append((cost, 0, i+1))
for u, v, w in pipes:
edges.append((w, u, v))
# Kruskal's algorithm
edges.sort()
parent = [i for i in range(n+1)]
def find(x):
while parent[x] != x:
parent[x] = parent[parent[x]]
x = parent[x]
return x
res = 0
for w, u, v in edges:
pu, pv = find(u), find(v)
if pu != pv:
parent[pu] = pv
res += w
return res
class Solution {
public:
int minCostToSupplyWater(int n, vector<int>& wells, vector<vector<int>>& pipes) {
vector<tuple<int,int,int>> edges;
for (int i = 0; i < n; ++i)
edges.emplace_back(wells[i], 0, i+1);
for (auto& p : pipes)
edges.emplace_back(p[2], p[0], p[1]);
sort(edges.begin(), edges.end());
vector<int> parent(n+1);
iota(parent.begin(), parent.end(), 0);
function<int(int)> find = [&](int x) {
while (parent[x] != x) {
parent[x] = parent[parent[x]];
x = parent[x];
}
return x;
};
int res = 0;
for (auto& [w, u, v] : edges) {
int pu = find(u), pv = find(v);
if (pu != pv) {
parent[pu] = pv;
res += w;
}
}
return res;
}
};
class Solution {
public int minCostToSupplyWater(int n, int[] wells, int[][] pipes) {
List<int[]> edges = new ArrayList<>();
for (int i = 0; i < n; ++i)
edges.add(new int[]{wells[i], 0, i+1});
for (int[] p : pipes)
edges.add(new int[]{p[2], p[0], p[1]});
edges.sort((a, b) -> a[0] - b[0]);
int[] parent = new int[n+1];
for (int i = 0; i <= n; ++i) parent[i] = i;
int res = 0;
for (int[] e : edges) {
int w = e[0], u = e[1], v = e[2];
int pu = find(parent, u), pv = find(parent, v);
if (pu != pv) {
parent[pu] = pv;
res += w;
}
}
return res;
}
private int find(int[] parent, int x) {
while (parent[x] != x) {
parent[x] = parent[parent[x]];
x = parent[x];
}
return x;
}
}
var minCostToSupplyWater = function(n, wells, pipes) {
let edges = [];
for (let i = 0; i < n; ++i)
edges.push([wells[i], 0, i+1]);
for (let [u, v, w] of pipes)
edges.push([w, u, v]);
edges.sort((a, b) => a[0] - b[0]);
let parent = Array(n+1).fill(0).map((_,i)=>i);
function find(x) {
while (parent[x] !== x) {
parent[x] = parent[parent[x]];
x = parent[x];
}
return x;
}
let res = 0;
for (let [w, u, v] of edges) {
let pu = find(u), pv = find(v);
if (pu !== pv) {
parent[pu] = pv;
res += w;
}
}
return res;
};
You are given n
houses in a village, numbered from 1
to n
. Each house needs access to water. There are two ways to supply water to a house:
wells[i]
(for house i+1
).pipes
. Each pipe is represented as [house1, house2, cost]
and can supply both houses if connected.Your task is to supply water to every house with the minimum total cost. You may build wells, lay pipes, or use a combination of both. Each pipe can only be used once, and you cannot reuse wells. There is always at least one valid way to supply water to all houses.
At first glance, the problem seems to ask for choosing the cheapest way to supply water to each house: either build a well or connect via pipes. But since pipes can connect multiple houses and share water, simply picking the cheapest option for each house independently may not yield the minimum total cost.
A brute-force approach would try all possible combinations of wells and pipes, but this quickly becomes impractical as the number of houses and pipes grows. Instead, we recognize this as a variation of the Minimum Spanning Tree (MST) problem, where each house is a node, pipes are edges, and building a well is like connecting the house to a virtual water source node.
The key insight is to model building a well as an edge from a virtual node (say, node 0) to each house, with the cost being the well's price. Then, we find the MST of this augmented graph: the minimum cost to connect all houses (and the water source) together.
i
, add an edge from node 0 to node i+1
with cost wells[i]
. All pipes are already edges between houses.
Suppose n = 3
, wells = [1,2,2]
, and pipes = [[1,2,1],[2,3,1]]
.
n
.
O(E \log E)
, where E
is the number of edges (pipes + wells).O(E)
due to path compression.O(E \log E)
time and O(n)
space for parent array.By modeling well-building as connecting houses to a virtual water source, the problem becomes a classic Minimum Spanning Tree scenario. Using Kruskal's algorithm efficiently finds the minimum cost to connect all houses to water, cleverly combining wells and pipes as needed. This approach is both elegant and optimal, leveraging well-known graph algorithms to solve a practical resource allocation problem.