2023-08-04:村里面一共有 n 栋房子

我们希望通过建造水井和铺设管道来为所有房子供水。

对于每个房子 i,我们有两种可选的供水方案:

一种是直接在房子内建造水井

成本为 wells[i - 1] (注意 -1 ,因为 索引从0开始 )

另一种是从另一口井铺设管道引水

数组 pipes 给出了在房子间铺设管道的成本

其中每个 pipes[j] = [house1j, house2j, costj]

代表用管道将 house1j 和 house2j连接在一起的成本。连接是双向的。

请返回 为所有房子都供水的最低总成本 。

这道题很高频,引起注意,

本身也不难,转化一下变成最小生成树的问题即可。

输入:n = 3, wells = [1,2,2], pipes = [[1,2,1],[2,3,1]]。

输出:3。

来自小红书、字节跳动。

答案2023-08-04:

大体过程如下:

1.初始化:

1.1.创建边数组 edges 用于存储管道的信息。

1.2.将每个房子 i 作为一个独立的连通分量,创建并查集的父数组 father[i] 初始化为 i。

1.3.创建每个房子的大小数组 size[i] 初始化为 1。

1.4.创建辅助数组 help 用于路径压缩。

2.构建边数组:

2.1.将每个房子 i 内建造水井的成本 wells[i-1] 加入边数组 edges。

2.2.将每个管道 [house1j, house2j, costj] 的信息加入边数组 edges。

3.对边数组进行排序:

3.1.根据边的成本从小到大对边数组 edges 进行排序。

4.构建并查集:

4.1.调用 build(n) 函数来初始化并查集。

5.最小生成树的构建与计算最低总成本:

5.1.初始化 ans = 0,用于记录最低总成本。

5.2.遍历边数组 edges,对于每条边 edges[i],执行以下步骤:

5.2.1.判断边 edges[i] 的两个节点是否连通(使用并查集中的 find() 函数):

5.2.1.1.若不连通,则将这两个节点合并(使用并查集中的 union() 函数)。

5.2.1.2.同时累加上该边的成本 edges[i][2] 到总成本 ans 中。

6.返回最低总成本 ans。

总的时间复杂度:O((n+m)log(n+m)),其中 n 是房子数量,m 是管道数量,因为对边数组进行了排序。

总的空间复杂度:O(n+m),其中 n 是房子数量,m 是管道数量(边的数量)。

go完整代码如下:

package main

import (
"fmt"
"sort"
) const MAXN = 10010 var edges [][3]int
var esize int
var father [MAXN]int
var size [MAXN]int
var help [MAXN]int func build(n int) {
for i := 0; i <= n; i++ {
father[i] = i
size[i] = 1
}
} func find(i int) int {
s := 0
for i != father[i] {
help[s] = i
i = father[i]
s++
}
for s > 0 {
s--
father[help[s]] = i
}
return i
} func union(i, j int) bool {
f1 := find(i)
f2 := find(j)
if f1 != f2 {
if size[f1] >= size[f2] {
father[f2] = f1
size[f1] += size[f2]
} else {
father[f1] = f2
size[f2] += size[f1]
}
return true
}
return false
} func minCostToSupplyWater(n int, wells []int, pipes [][]int) int {
esize = 0
for i := 0; i < n; i++ {
edges = append(edges, [3]int{0, i + 1, wells[i]})
esize++
}
for i := 0; i < len(pipes); i++ {
edges = append(edges, [3]int{pipes[i][0], pipes[i][1], pipes[i][2]})
esize++
}
sort.Slice(edges, func(i, j int) bool {
return edges[i][2] < edges[j][2]
})
build(n)
ans := 0
for i := 0; i < esize; i++ {
if union(edges[i][0], edges[i][1]) {
ans += edges[i][2]
}
}
return ans
} func main() {
n := 3
wells := []int{1, 2, 2}
pipes := [][]int{{1, 2, 1}, {2, 3, 1}} result := minCostToSupplyWater(n, wells, pipes)
fmt.Println(result)
}

rust代码如下:

const MAXN: i32 = 10010;

static mut EDGES: [[i32; 3]; (MAXN << 1) as usize] = [[0; 3]; (MAXN << 1) as usize];
static mut ESIZE: i32 = 0; static mut FATHER: [i32; MAXN as usize] = [0; MAXN as usize];
static mut SIZE: [i32; MAXN as usize] = [0; MAXN as usize];
static mut HELP: [i32; MAXN as usize] = [0; MAXN as usize]; fn build(n: i32) {
for i in 0..=n {
unsafe {
FATHER[i as usize] = i;
SIZE[i as usize] = 1;
}
}
} fn find(i: i32) -> i32 {
let mut s = 0;
unsafe {
let mut index = i;
while index != FATHER[index as usize] {
HELP[s] = index;
index = FATHER[index as usize];
s += 1;
}
while s > 0 {
s -= 1;
FATHER[HELP[s] as usize] = index;
}
return index;
}
} fn union(i: i32, j: i32) -> bool {
let f1 = find(i);
let f2 = find(j);
unsafe {
if f1 != f2 {
if SIZE[f1 as usize] >= SIZE[f2 as usize] {
FATHER[f2 as usize] = f1;
SIZE[f1 as usize] += SIZE[f2 as usize];
} else {
FATHER[f1 as usize] = f2;
SIZE[f2 as usize] += SIZE[f1 as usize];
}
return true;
} else {
return false;
}
}
} fn min_cost_to_supply_water(n: i32, wells: &[i32], pipes: &[[i32; 3]]) -> i32 {
unsafe {
ESIZE = 0;
for i in 0..n {
EDGES[ESIZE as usize][0] = 0;
EDGES[ESIZE as usize][1] = i + 1;
EDGES[ESIZE as usize][2] = wells[i as usize];
ESIZE += 1;
}
for i in 0..pipes.len() {
EDGES[ESIZE as usize][0] = pipes[i][0] as i32;
EDGES[ESIZE as usize][1] = pipes[i][1] as i32;
EDGES[ESIZE as usize][2] = pipes[i][2];
ESIZE += 1;
}
EDGES[0..ESIZE as usize].sort_by(|a, b| a[2].cmp(&b[2]));
build(n);
let mut ans = 0;
for i in 0..ESIZE {
if union(EDGES[i as usize][0], EDGES[i as usize][1]) {
ans += EDGES[i as usize][2];
}
}
return ans;
}
} fn main() {
let n = 3;
let wells = [1, 2, 2];
let pipes = [[1, 2, 1], [2, 3, 1]];
let result = min_cost_to_supply_water(n, &wells, &pipes);
println!("Minimum cost to supply water: {}", result);
}

c++完整代码如下:

#include <iostream>
#include <vector>
#include <array>
#include <algorithm>
using namespace std; const int MAXN = 10010;
vector<array<int, 3>> edges;
int father[MAXN];
int size2[MAXN];
int help[MAXN]; void build(int n) {
for (int i = 0; i <= n; i++) {
father[i] = i;
size2[i] = 1;
}
} int find(int i) {
int s = 0;
while (i != father[i]) {
help[s++] = i;
i = father[i];
}
while (s > 0) {
father[help[--s]] = i;
}
return i;
} bool unionSet(int i, int j) {
int f1 = find(i);
int f2 = find(j);
if (f1 != f2) {
if (size2[f1] >= size2[f2]) {
father[f2] = f1;
size2[f1] += size2[f2];
}
else {
father[f1] = f2;
size2[f2] += size2[f1];
}
return true;
}
else {
return false;
}
} int minCostToSupplyWater(int n, vector<int>& wells, vector<vector<int>>& pipes) {
edges.clear();
for (int i = 0; i < n; i++) {
edges.push_back({ 0, i + 1, wells[i] });
}
for (int i = 0; i < pipes.size(); i++) {
edges.push_back({ pipes[i][0], pipes[i][1], pipes[i][2] });
}
sort(edges.begin(), edges.end(), [](const array<int, 3>& a, const array<int, 3>& b) {
return a[2] < b[2];
});
build(n);
int ans = 0;
for (int i = 0; i < edges.size(); i++) {
if (unionSet(edges[i][0], edges[i][1])) {
ans += edges[i][2];
}
}
return ans;
} int main() {
int n = 3;
vector<int> wells = { 1, 2, 2 };
vector<vector<int>> pipes = { {1, 2, 1}, {2, 3, 1} };
int result = minCostToSupplyWater(n, wells, pipes);
cout << "Minimum cost to supply water: " << result << endl;
return 0;
}

c完整代码如下:

#include <stdio.h>
#include <stdlib.h> #define MAXN 10010 int edges[MAXN << 1][3];
int esize;
int father[MAXN];
int size[MAXN];
int help[MAXN]; void build(int n) {
for (int i = 0; i <= n; i++) {
father[i] = i;
size[i] = 1;
}
} int find(int i) {
int s = 0;
while (i != father[i]) {
help[s++] = i;
i = father[i];
}
while (s > 0) {
father[help[--s]] = i;
}
return i;
} int union2(int i, int j) {
int f1 = find(i);
int f2 = find(j);
if (f1 != f2) {
if (size[f1] >= size[f2]) {
father[f2] = f1;
size[f1] += size[f2];
}
else {
father[f1] = f2;
size[f2] += size[f1];
}
return 1;
}
else {
return 0;
}
} int minCostToSupplyWater(int n, int wells[], int pipes[][3], int pipesSize) {
esize = 0;
for (int i = 0; i < n; i++, esize++) {
edges[esize][0] = 0;
edges[esize][1] = i + 1;
edges[esize][2] = wells[i];
}
for (int i = 0; i < pipesSize; i++, esize++) {
edges[esize][0] = pipes[i][0];
edges[esize][1] = pipes[i][1];
edges[esize][2] = pipes[i][2];
} // Sort edges based on the third column (weights)
for (int i = 0; i < esize; i++) {
for (int j = 0; j < esize - 1; j++) {
if (edges[j][2] > edges[j + 1][2]) {
int temp[3];
temp[0] = edges[j][0];
temp[1] = edges[j][1];
temp[2] = edges[j][2];
edges[j][0] = edges[j + 1][0];
edges[j][1] = edges[j + 1][1];
edges[j][2] = edges[j + 1][2];
edges[j + 1][0] = temp[0];
edges[j + 1][1] = temp[1];
edges[j + 1][2] = temp[2];
}
}
} build(n);
int ans = 0;
for (int i = 0; i < esize; i++) {
if (union2(edges[i][0], edges[i][1])) {
ans += edges[i][2];
}
}
return ans;
} int main() {
int n = 3;
int wells[] = { 1, 2, 2 };
int pipes[][3] = { {1, 2, 1}, {2, 3, 1} };
int pipesSize = sizeof(pipes) / sizeof(pipes[0]); int result = minCostToSupplyWater(n, wells, pipes, pipesSize);
printf("Minimum cost to supply water: %d\n", result); return 0;
}

2023-08-04:村里面一共有 n 栋房子 我们希望通过建造水井和铺设管道来为所有房子供水。 对于每个房子 i,我们有两种可选的供水方案: 一种是直接在房子内建造水井 成本为 wells[i -的更多相关文章

  1. 分布式ID详解(5种分布式ID生成方案)

    分布式架构会涉及到分布式全局唯一ID的生成,今天我就来详解分布式全局唯一ID,以及分布式全局唯一ID的实现方案@mikechen 什么是分布式系统唯一ID 在复杂分布式系统中,往往需要对大量的数据和消 ...

  2. 北京设计模式学习组bjdp.org第7次活动(2013.08.04)回顾会纪要

    时间:2013.08.04,9am-7pm 地点:北京龙泉寺(北京凤凰岭风景区内) 参加人数:北京龙泉寺信息中心(20人).北京设计模式学习组(9人) 活动要点: 1)寺院巡礼:义工师兄带领参观寺院. ...

  3. 深度点评五种常见WiFi搭建方案

    总结十年无线搭建经验,针对企业常见的五种办公室无线网络方案做个简要分析,各种方案有何优劣,又适用于那种类型的企业. 方案一:仅路由器或AP覆盖 简述:使用路由器或AP覆盖多个无线盲区,多个AP的部署实 ...

  4. 三种UIScrollView嵌套实现方案

    背景 随着产品功能不断的迭代,总会有需求希望在保证不影响其他区域功能的前提下,在某一区域实现根据选择器切换不同的内容显示. 苹果并不推荐嵌套滚动视图,如果直接添加的话,就会出现下图这种情况,手势的冲突 ...

  5. (转载)MySQL数据库的几种常见高可用方案

    转自: https://yq.aliyun.com/articles/74454   随着人们对数据一致性的要求不断的提高,越来越多的方法被尝试用来解决分布式数据一致性的问题,如MySQL自身的优化. ...

  6. 新手C#string类常用函数的学习2018.08.04

    ToLower()用于将字符串变为小写,注意字符串的不可变特性,需要重新赋值给另一个字符串变量. s = s.ToLower();//字符串具有不可变性,转换后需要重新赋值,不可仅有s.ToLower ...

  7. 新手C#int.Parse、int.TryParse的学习2018.08.04

    int.Parse()用于将字符串转换为32为int类型,但是在遇到非数字或者类似1.545这种小数的时候会报错,后来采用了int.TryParse,这个在转换后会判断是否可以正常转换,若不能,会返回 ...

  8. 新手C#参数类型ref、out、params的学习2018.08.04

    ref用于传递参数时,将实参传递到函数中,是引用参数,在使用前必须被赋值.string类型也同样适用. static void Main(string[] args) { string a1,a2; ...

  9. 新手C#重载、重写的学习2018.08.04

    重载:在同一类(class)中,使用相同的方法名称,不同的参数和(不一定)不同的返回值类型构造成的方法. 举例: class OverLoadTest { public void Hello() { ...

  10. 单页应用SPA做SEO的一种清奇的方案

    单页应用SPA做SEO的一种清奇的方案 网上有好几种单页应用转seo的方案,有服务端渲染ssr.有预渲染prerender.google抓AJAX.静态化...这些方案都各有优劣,开发者可以根据不同的 ...

随机推荐

  1. 求解 LCA の方法

    最近公共祖先(LCA) 最近公共祖先简称 LCA(Lowest Common Ancestor).两个节点的最近公共祖先,就是这两个点的公共祖先里面,离根最远的那个. -----oi wiki 举个例 ...

  2. Unity快速接入bugly, 支持Unity2021

    鹅厂提供的bugly官方demo工程打包后台也查不到日志,N年不更新(官方已经说不再维护),为此本人做了部分修改测试,提供一个快速接入工程的demo. Unity2021因为版本原因腾讯官方工程不能使 ...

  3. 2022-11-11:设计一个最大栈数据结构,既支持栈操作,又支持查找栈中最大元素。 实现 MaxStack 类: MaxStack() 初始化栈对象 void push(int x) 将元素 x 压

    2022-11-11:设计一个最大栈数据结构,既支持栈操作,又支持查找栈中最大元素. 实现 MaxStack 类: MaxStack() 初始化栈对象 void push(int x) 将元素 x 压 ...

  4. 2020-08-13:Hadoop生态圈的了解?

    福哥答案2020-08-13: 该项目包括以下模块:1.Common(公共工具)支持其他Hadoop模块的公共工具. 2.HDFS(Hadoop分布式文件系统)提供对应用程序数据的高吞吐量访问的分布式 ...

  5. 2021-02-04:第一年农场有1只成熟的母牛A,往后的每年:①每一只成熟的母牛都会生一只母牛 ②每一只新出生的母牛都在出生的第三年成熟 ③每一只母牛永远不会死 。请问N年后牛的数量是多少 ?

    2021-02-04:第一年农场有1只成熟的母牛A,往后的每年:①每一只成熟的母牛都会生一只母牛 ②每一只新出生的母牛都在出生的第三年成熟 ③每一只母牛永远不会死 .请问N年后牛的数量是多少 ?福哥答 ...

  6. 2022-03-04:爱吃香蕉的珂珂。 珂珂喜欢吃香蕉。这里有 N 堆香蕉,第 i 堆中有 piles[i] 根香蕉。警卫已经离开了,将在 H 小时后回来。 珂珂可以决定她吃香蕉的速度 K (单位:根

    2022-03-04:爱吃香蕉的珂珂. 珂珂喜欢吃香蕉.这里有 N 堆香蕉,第 i 堆中有 piles[i] 根香蕉.警卫已经离开了,将在 H 小时后回来. 珂珂可以决定她吃香蕉的速度 K (单位:根 ...

  7. 2021-08-28:给定一个正数数组arr,长度一定大于6(>=7),一定要选3个数字做分割点,从而分出4个部分,并且每部分都有数,分割点的数字直接删除,不属于任何4个部分中的任何一个。 返回有没有

    2021-08-28:给定一个正数数组arr,长度一定大于6(>=7),一定要选3个数字做分割点,从而分出4个部分,并且每部分都有数,分割点的数字直接删除,不属于任何4个部分中的任何一个. 返回 ...

  8. vue全家桶进阶之路35:Vue3 传递参数query和params

    在 Vue.js 3.x 中,可以通过路由的 params 和 query 属性来传递参数. 通过 params 传递参数 我们可以在路由跳转时通过 params 传递参数.具体方法如下: // 在组 ...

  9. 【GiraKoo】Git工具使用指南

    Git工具使用指南 Git是一个分布式版本控制工具,可以用于管理代码.本文介绍了如何使用git工具. 1. SVN和Git的区别 1.1 SVN SVN是集中式版本控制工具,所有的代码都存储在一个中央 ...

  10. ESlint配置详解

    开发中出现eslint提示代码格式错误,有时候不明白其配置规范,是件很头疼的事情到处找api又是半天:so记录一份配置详情便于开发中翻阅 { // 环境定义了预定义的全局变量. "env&q ...