Skip to content

Commit 9f696cd

Browse files
committed
feat: add solutions to lc problem: No.1168.Optimize Water Distribution
in a Village
1 parent ae5883f commit 9f696cd

File tree

7 files changed

+457
-6
lines changed

7 files changed

+457
-6
lines changed

basic/searching/BinarySearch/README.md

+5-3
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,13 @@ int search(int left, int right) {
4444

4545
1. 写出循环条件:`while (left < right)`,注意是 `left < right`,而非 `left <= right`
4646
1. 循环体内,先无脑写出 `mid = (left + right) >> 1`
47-
1. 根据具体题目,实现 `check()` 函数(有时很简单的逻辑,可以不定义函数),想一下究竟要用 `left = mid`模板二) 还是 `right = mid`模板一);
48-
- 如果 `left = mid`,那么无脑写出 else 语句 `right = mid - 1`并且在 mid 计算时补充 +1,即 `mid = (left + right + 1) >> 1`
49-
- 如果 `right = mid`,那么无脑写出 else 语句 `left = mid + 1`并且不需要更改 mid 的计算;
47+
1. 根据具体题目,实现 `check()` 函数(有时很简单的逻辑,可以不定义 `check`),想一下究竟要用 `right = mid`模板 1) 还是 `left = mid`模板 2);
48+
- 如果 `right = mid`,那么无脑写出 else 语句 `left = mid + 1`并且不需要更改 mid 的计算,即保持 `mid = (left + right) >> 1`
49+
- 如果 `left = mid`,那么无脑写出 else 语句 `right = mid - 1`并且在 mid 计算时补充 +1,即 `mid = (left + right + 1) >> 1`
5050
1. 循环结束时,left 与 right 相等。
5151

52+
注意,这两个模板的优点是始终保持答案位于二分区间内,二分结束条件对应的值恰好在答案所处的位置。 对于可能无解的情况,只要判断二分结束后的 left 或者 right 是否满足题意即可。
53+
5254
## 例题
5355

5456
- [在排序数组中查找元素的第一个和最后一个位置](/solution/0000-0099/0034.Find%20First%20and%20Last%20Position%20of%20Element%20in%20Sorted%20Array/README.md)

solution/1100-1199/1168.Optimize Water Distribution in a Village/README.md

+193-1
Original file line numberDiff line numberDiff line change
@@ -44,27 +44,219 @@
4444
<li><code>pipes[i][0] != pipes[i][1]</code></li>
4545
</ul>
4646

47-
4847
## 解法
4948

5049
<!-- 这里可写通用的实现逻辑 -->
5150

51+
并查集。
52+
53+
模板 1——朴素并查集:
54+
55+
```python
56+
# 初始化,p存储每个点的父节点
57+
p = list(range(n))
58+
59+
# 返回x的祖宗节点
60+
def find(x):
61+
if p[x] != x:
62+
# 路径压缩
63+
p[x] = find(p[x])
64+
return p[x]
65+
66+
# 合并a和b所在的两个集合
67+
p[find(a)] = find(b)
68+
```
69+
70+
模板 2——维护 size 的并查集:
71+
72+
```python
73+
# 初始化,p存储每个点的父节点,size只有当节点是祖宗节点时才有意义,表示祖宗节点所在集合中,点的数量
74+
p = list(range(n))
75+
size = [1] * n
76+
77+
# 返回x的祖宗节点
78+
def find(x):
79+
if p[x] != x:
80+
# 路径压缩
81+
p[x] = find(p[x])
82+
return p[x]
83+
84+
# 合并a和b所在的两个集合
85+
if find(a) != find(b):
86+
size[find(b)] += size[find(a)]
87+
p[find(a)] = find(b)
88+
```
89+
90+
模板 3——维护到祖宗节点距离的并查集:
91+
92+
```python
93+
# 初始化,p存储每个点的父节点,d[x]存储x到p[x]的距离
94+
p = list(range(n))
95+
d = [0] * n
96+
97+
# 返回x的祖宗节点
98+
def find(x):
99+
if p[x] != x:
100+
t = find(p[x])
101+
d[x] += d[p[x]]
102+
p[x] = t
103+
return p[x]
104+
105+
# 合并a和b所在的两个集合
106+
p[find(a)] = find(b)
107+
d[find(a)] = distance
108+
```
109+
110+
对于本题,可以将节点 0 视为水库,水库到房子间的成本等于房子内建造水井的成本。因此此题可以转换为最小生成树问题。
111+
52112
<!-- tabs:start -->
53113

54114
### **Python3**
55115

56116
<!-- 这里可写当前语言的特殊实现逻辑 -->
57117

58118
```python
119+
class Solution:
120+
def minCostToSupplyWater(self, n: int, wells: List[int], pipes: List[List[int]]) -> int:
121+
for i, w in enumerate(wells):
122+
pipes.append([0, i + 1, w])
123+
pipes.sort(key=lambda x: x[2])
124+
125+
p = list(range(n + 1))
59126

127+
def find(x):
128+
if p[x] != x:
129+
p[x] = find(p[x])
130+
return p[x]
131+
132+
res = 0
133+
for u, v, w in pipes:
134+
if find(u) == find(v):
135+
continue
136+
p[find(u)] = find(v)
137+
res += w
138+
n -= 1
139+
if n == 0:
140+
break
141+
return res
60142
```
61143

62144
### **Java**
63145

64146
<!-- 这里可写当前语言的特殊实现逻辑 -->
65147

66148
```java
149+
class Solution {
150+
private int[] p;
151+
152+
public int minCostToSupplyWater(int n, int[] wells, int[][] pipes) {
153+
int[][] all = new int[pipes.length + n][3];
154+
int idx = 0;
155+
for (int[] pipe : pipes) {
156+
all[idx++] = pipe;
157+
}
158+
for (int j = 0; j < n; ++j) {
159+
all[idx++] = new int[]{0, j + 1, wells[j]};
160+
}
161+
p = new int[n + 1];
162+
for (int i = 0; i < p.length; ++i) {
163+
p[i] = i;
164+
}
165+
Arrays.sort(all, Comparator.comparingInt(a -> a[2]));
166+
int res = 0;
167+
for (int[] e : all) {
168+
if (find(e[0]) == find(e[1])) {
169+
continue;
170+
}
171+
p[find(e[0])] = find(e[1]);
172+
res += e[2];
173+
--n;
174+
if (n == 0) {
175+
break;
176+
}
177+
}
178+
return res;
179+
}
180+
181+
private int find(int x) {
182+
if (p[x] != x) {
183+
p[x] = find(p[x]);
184+
}
185+
return p[x];
186+
}
187+
}
188+
```
189+
190+
### **C++**
191+
192+
```cpp
193+
class Solution {
194+
public:
195+
vector<int> p;
196+
197+
int minCostToSupplyWater(int n, vector<int>& wells, vector<vector<int>>& pipes) {
198+
p.resize(n + 1);
199+
for (int i = 0; i < p.size(); ++i) p[i] = i;
200+
for (int i = 0; i < n; ++i) pipes.push_back({0, i + 1, wells[i]});
201+
sort(pipes.begin(), pipes.end(), [](const auto& a, const auto& b) {
202+
return a[2] < b[2];
203+
});
204+
int res = 0;
205+
for (auto e : pipes)
206+
{
207+
if (find(e[0]) == find(e[1])) continue;
208+
p[find(e[0])] = find(e[1]);
209+
res += e[2];
210+
--n;
211+
if (n == 0) break;
212+
}
213+
return res;
214+
}
215+
216+
int find(int x) {
217+
if (p[x] != x) p[x] = find(p[x]);
218+
return p[x];
219+
}
220+
};
221+
```
222+
223+
### **Go**
224+
225+
```go
226+
var p []int
227+
228+
func minCostToSupplyWater(n int, wells []int, pipes [][]int) int {
229+
p = make([]int, n+1)
230+
for i := 0; i < len(p); i++ {
231+
p[i] = i
232+
}
233+
for i, w := range wells {
234+
pipes = append(pipes, []int{0, i + 1, w})
235+
}
236+
sort.Slice(pipes, func(i, j int) bool {
237+
return pipes[i][2] < pipes[j][2]
238+
})
239+
res := 0
240+
for _, e := range pipes {
241+
if find(e[0]) == find(e[1]) {
242+
continue
243+
}
244+
p[find(e[0])] = find(e[1])
245+
res += e[2]
246+
n--
247+
if n == 0 {
248+
break
249+
}
250+
}
251+
return res
252+
}
67253
254+
func find(x int) int {
255+
if p[x] != x {
256+
p[x] = find(p[x])
257+
}
258+
return p[x]
259+
}
68260
```
69261

70262
### **...**

solution/1100-1199/1168.Optimize Water Distribution in a Village/README_EN.md

+135-2
Original file line numberDiff line numberDiff line change
@@ -37,21 +37,154 @@ The best strategy is to build a well in the first house with cost 1 and connect
3737
<li><code>house1<sub>j</sub> != house2<sub>j</sub></code></li>
3838
</ul>
3939

40-
4140
## Solutions
4241

42+
Union find.
43+
4344
<!-- tabs:start -->
4445

4546
### **Python3**
4647

4748
```python
48-
49+
class Solution:
50+
def minCostToSupplyWater(self, n: int, wells: List[int], pipes: List[List[int]]) -> int:
51+
for i, w in enumerate(wells):
52+
pipes.append([0, i + 1, w])
53+
pipes.sort(key=lambda x: x[2])
54+
55+
p = list(range(n + 1))
56+
57+
def find(x):
58+
if p[x] != x:
59+
p[x] = find(p[x])
60+
return p[x]
61+
62+
res = 0
63+
for u, v, w in pipes:
64+
if find(u) == find(v):
65+
continue
66+
p[find(u)] = find(v)
67+
res += w
68+
n -= 1
69+
if n == 0:
70+
break
71+
return res
4972
```
5073

5174
### **Java**
5275

5376
```java
77+
class Solution {
78+
private int[] p;
79+
80+
public int minCostToSupplyWater(int n, int[] wells, int[][] pipes) {
81+
int[][] all = new int[pipes.length + n][3];
82+
int idx = 0;
83+
for (int[] pipe : pipes) {
84+
all[idx++] = pipe;
85+
}
86+
for (int j = 0; j < n; ++j) {
87+
all[idx++] = new int[]{0, j + 1, wells[j]};
88+
}
89+
p = new int[n + 1];
90+
for (int i = 0; i < p.length; ++i) {
91+
p[i] = i;
92+
}
93+
Arrays.sort(all, Comparator.comparingInt(a -> a[2]));
94+
int res = 0;
95+
for (int[] e : all) {
96+
if (find(e[0]) == find(e[1])) {
97+
continue;
98+
}
99+
p[find(e[0])] = find(e[1]);
100+
res += e[2];
101+
--n;
102+
if (n == 0) {
103+
break;
104+
}
105+
}
106+
return res;
107+
}
108+
109+
private int find(int x) {
110+
if (p[x] != x) {
111+
p[x] = find(p[x]);
112+
}
113+
return p[x];
114+
}
115+
}
116+
```
117+
118+
### **C++**
119+
120+
```cpp
121+
class Solution {
122+
public:
123+
vector<int> p;
124+
125+
int minCostToSupplyWater(int n, vector<int>& wells, vector<vector<int>>& pipes) {
126+
p.resize(n + 1);
127+
for (int i = 0; i < p.size(); ++i) p[i] = i;
128+
for (int i = 0; i < n; ++i) pipes.push_back({0, i + 1, wells[i]});
129+
sort(pipes.begin(), pipes.end(), [](const auto& a, const auto& b) {
130+
return a[2] < b[2];
131+
});
132+
int res = 0;
133+
for (auto e : pipes)
134+
{
135+
if (find(e[0]) == find(e[1])) continue;
136+
p[find(e[0])] = find(e[1]);
137+
res += e[2];
138+
--n;
139+
if (n == 0) break;
140+
}
141+
return res;
142+
}
143+
144+
int find(int x) {
145+
if (p[x] != x) p[x] = find(p[x]);
146+
return p[x];
147+
}
148+
};
149+
```
54150
151+
### **Go**
152+
153+
```go
154+
var p []int
155+
156+
func minCostToSupplyWater(n int, wells []int, pipes [][]int) int {
157+
p = make([]int, n+1)
158+
for i := 0; i < len(p); i++ {
159+
p[i] = i
160+
}
161+
for i, w := range wells {
162+
pipes = append(pipes, []int{0, i + 1, w})
163+
}
164+
sort.Slice(pipes, func(i, j int) bool {
165+
return pipes[i][2] < pipes[j][2]
166+
})
167+
res := 0
168+
for _, e := range pipes {
169+
if find(e[0]) == find(e[1]) {
170+
continue
171+
}
172+
p[find(e[0])] = find(e[1])
173+
res += e[2]
174+
n--
175+
if n == 0 {
176+
break
177+
}
178+
}
179+
return res
180+
}
181+
182+
func find(x int) int {
183+
if p[x] != x {
184+
p[x] = find(p[x])
185+
}
186+
return p[x]
187+
}
55188
```
56189

57190
### **...**

0 commit comments

Comments
 (0)