2023-10-04:用go语言,现有一棵无向、无根的树,树中有 n 个节点,按从 0 到 n - 1 编号

给你一个整数 n 和一个长度为 n - 1 的二维整数数组 edges ,

其中 edges[i] = [ai, bi] 表示树中节点 ai 和 bi 之间存在一条边。

每个节点都关联一个价格。给你一个整数数组 price ,其中 price[i] 是第 i 个节点的价格。

给定路径的 价格总和 是该路径上所有节点的价格之和。

另给你一个二维整数数组 trips ,其中 trips[i] = [starti, endi] 表示

从节点 starti 开始第 i 次旅行,并通过任何你喜欢的路径前往节点 endi 。

在执行第一次旅行之前,你可以选择一些 非相邻节点 并将价格减半。

返回执行所有旅行的最小价格总和。

输入:n = 4, edges = [[0,1],[1,2],[1,3]], price = [2,2,10,6], trips = [[0,3],[2,1],[2,3]]。

输出:23。

来自左程云

答案2023-10-04:

大体过程如下:

1.构建图:根据输入的edges构建无向图,使用邻接表存储每个节点的邻居节点。

2.初始化查询数组:根据trips初始化查询数组,将每个旅行的起点和终点加入到对应节点的查询数组中。

3.初始化并查集:初始化一个并查集,用于保存节点的父节点信息和标签。将每个节点的父节点初始化为自身,标签初始化为-1。

4.进行Tarjan算法:从根节点开始遍历树,使用递归的方式进行深度优先搜索。

  • 对于每个节点cur,记录其父节点father。

  • 遍历cur的邻居节点next,如果next不等于father,进行递归操作。

  • 递归操作结束后,将cur和next节点合并,设置它们的标签为cur。

  • 对于cur节点的查询数组中的每个查询,如果查询的终点的标签不为-1,说明该查询经过cur节点,记录查询的终点标签为最低公共祖先节点。

5.计算每个节点的旅行个数:遍历旅行数组,统计每个节点作为起点或终点的旅行个数。

  • 对于每个旅行,起点和终点的旅行个数加1,最低公共祖先节点的旅行个数减1。

  • 如果最低公共祖先节点的父节点不为-1,最低公共祖先节点的父节点的旅行个数减1。

6.使用深度优先搜索计算价格总和:从根节点开始,使用递归的方式进行深度优先搜索。

  • 对于每个节点cur,计算不选择减半价格的情况下的总价格no和选择减半价格的情况下的总价格

  • 遍历cur的邻居节点next,如果next不等于father,进行递归操作。

  • 更新no和yes的值。

7.返回最小价格总和:取no和yes中较小的值作为最小价格总和。

总的时间复杂度:O(n)(遍历节点和邻居节点) + O(m)(遍历查询数组) + O(n)(遍历旅行数组) + O(n)(遍历节点和邻居节点) = O(n + m)

总的额外空间复杂度:O(n)(存储图) + O(m)(存储查询数组) + O(n)(存储父节点信息) + O(n)(存储旅行个数) + O(n)(存储价格总和) = O(n + m)

go完整代码如下:

package main

import (
"fmt"
"math"
) func minimumTotalPrice(n int, edges [][]int, price []int, trips [][]int) int {
graph := make([][]int, n)
queries := make([][][]int, n)
for i := 0; i < n; i++ {
graph[i] = make([]int, 0)
queries[i] = make([][]int, 0)
}
for _, edge := range edges {
graph[edge[0]] = append(graph[edge[0]], edge[1])
graph[edge[1]] = append(graph[edge[1]], edge[0])
}
m := len(trips)
lcs := make([]int, m)
for i := 0; i < m; i++ {
if trips[i][0] == trips[i][1] {
lcs[i] = trips[i][0]
} else {
queries[trips[i][0]] = append(queries[trips[i][0]], []int{trips[i][1], i})
queries[trips[i][1]] = append(queries[trips[i][1]], []int{trips[i][0], i})
}
}
uf := &UnionFind{}
uf.init(n)
fathers := make([]int, n)
tarjan(graph, 0, -1, uf, queries, fathers, lcs)
cnts := make([]int, n)
for i := 0; i < m; i++ {
cnts[trips[i][0]]++
cnts[trips[i][1]]++
cnts[lcs[i]]--
if fathers[lcs[i]] != -1 {
cnts[fathers[lcs[i]]]--
}
}
dfs(graph, 0, -1, cnts)
ans := dp(graph, 0, -1, cnts, price)
return int(math.Min(float64(ans[0]), float64(ans[1])))
} func tarjan(graph [][]int, cur int, father int, uf *UnionFind, queries [][][]int, fathers []int, lcs []int) {
fathers[cur] = father
for _, next := range graph[cur] {
if next != father {
tarjan(graph, next, cur, uf, queries, fathers, lcs)
uf.union(cur, next)
uf.setTag(cur, cur)
}
}
for _, query := range queries[cur] {
tag := uf.getTag(query[0])
if tag != -1 {
lcs[query[1]] = tag
}
}
} func dfs(graph [][]int, cur int, father int, cnts []int) {
for _, next := range graph[cur] {
if next != father {
dfs(graph, next, cur, cnts)
cnts[cur] += cnts[next]
}
}
} func dp(graph [][]int, cur int, father int, cnts []int, price []int) []int {
no := price[cur] * cnts[cur]
yes := (price[cur] / 2) * cnts[cur]
for _, next := range graph[cur] {
if next != father {
nextAns := dp(graph, next, cur, cnts, price)
no += int(math.Min(float64(nextAns[0]), float64(nextAns[1])))
yes += nextAns[0]
}
}
return []int{no, yes}
} type UnionFind struct {
father []int
size []int
tag []int
help []int
} func (uf *UnionFind) init(n int) {
uf.father = make([]int, n)
uf.size = make([]int, n)
uf.tag = make([]int, n)
uf.help = make([]int, n)
for i := 0; i < n; i++ {
uf.father[i] = i
uf.size[i] = 1
uf.tag[i] = -1
}
} func (uf *UnionFind) find(i int) int {
size := 0
for i != uf.father[i] {
uf.help[size] = i
i = uf.father[i]
size++
}
for size > 0 {
size--
uf.father[uf.help[size]] = i
}
return i
} func (uf *UnionFind) union(i, j int) {
fi := uf.find(i)
fj := uf.find(j)
if fi != fj {
if uf.size[fi] >= uf.size[fj] {
uf.father[fj] = fi
uf.size[fi] += uf.size[fj]
} else {
uf.father[fi] = fj
uf.size[fj] += uf.size[fi]
}
}
} func (uf *UnionFind) setTag(i, t int) {
uf.tag[uf.find(i)] = t
} func (uf *UnionFind) getTag(i int) int {
return uf.tag[uf.find(i)]
} func main() {
n := 4
edges := [][]int{{0, 1}, {1, 2}, {1, 3}}
price := []int{2, 2, 10, 6}
trips := [][]int{{0, 3}, {2, 1}, {2, 3}}
result := minimumTotalPrice(n, edges, price, trips)
fmt.Println(result)
}

2023-10-04:用go语言,现有一棵无向、无根的树,树中有 n 个节点,按从 0 到 n - 1 编号 给你一个整数 n 和一个长度为 n - 1 的二维整数数组 edges , 其中 edge的更多相关文章

  1. 计算机二级-C语言-程序填空题-190109记录-对二维字符串数组的处理

    //给定程序,函数fun的功能是:求出形参ss所指字符串数组中最长字符串的长度,将其余字符串右边用字符*补齐,使其与最长的字符串等长.ss所指字符串数组中共有M个字符串,且串长<N. //重难点 ...

  2. 子串查询(二维前缀数组) 2018"百度之星"程序设计大赛 - 资格赛

    子串查询 Time Limit: 3500/3000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)Total Subm ...

  3. 【C/C++】二维数组的传参的方法/二维字符数组的声明,使用,输入,传参

    [问题] 定义了一个子函数,传参的内容是一个二维数组 编译提示错误 因为多维数组作为形参传入时,必须声明除第一位维外的确定值,否则系统无法编译(算不出偏移地址) [二维数组的传参] 方法一:形参为二维 ...

  4. Task 4.4二维环形数组求最大子矩阵之和

    任务: (1)输入一个二维整形数组,数组里有正数也有负数. (2)二维数组首尾相接,象个一条首尾相接带子一样. (3)数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和. (4)求所有子数 ...

  5. 分配一维动态数组or 二维动态数组的方法以及学习 new 方法or vector

    先来个开胃菜 // 使用new动态分配存储空间 #include<iostream> using std::cout; int main() { // 第1种方式 int *a=new i ...

  6. PHP二维关联数组的遍历方式

    采用foreach循环对二维索引数组进行遍历,相对来讲速度更快,效率更高,foreach循环是PHP中专门用来循环数组的.实例也相对简单,多加练习,想清楚程序运行逻辑即可. <?php $arr ...

  7. C++ 指针二维数组, C++二维指针数组笔记

    C++ 二维动态数组 一. 已知第一维 #include <iostream> using namespace std; int main(int argc, char const *ar ...

  8. 二维字符数组利用gets()函数输入

    举例: ][]; ;i<;i++) gets(a[i]); a是二维字符数组的数组名,相当于一维数组的指针, 所以a[i]就相当于指向第i个数组的指针,类型就相当于char *,相当于字符串.

  9. go 动态数组 二维动态数组

    go使用动态数组还有点麻烦,比python麻烦一点,需要先定义. 动态数组申明 var dynaArr []string 动态数组添加成员 dynaArr = append(dynaArr, &quo ...

  10. 求一个二维整数数组最大子数组之和,时间复杂度为N^2

    本随笔只由于时间原因,我就只写写思想了 二维数组最大子数组之和,可以  引用  一维最大子数组之和 的思想一维最大子数组之和 的思想,在本博客上有,这里就不做多的介绍了 我们有一个最初的二维数组a[n ...

随机推荐

  1. 使用C#编写.NET分析器-第二部分

    译者注 这是在Datadog公司任职的Kevin Gosse大佬使用C#编写.NET分析器的系列文章之一,在国内只有很少很少的人了解和研究.NET分析器,它常被用于APM(应用性能诊断).IDE.诊断 ...

  2. Nginx使用Lua脚本加解密RSA字符串

    本文主要介绍使用Lua脚本对采用RSA加密后的字符串进行解密的过程. 使用第三方类库lua-resty-rsa,参考地址:https://github.com/spacewander/lua-rest ...

  3. Elasticsearch日常开发

    2020-08-12 14:51:37 每次遇到ES开发,一般都是查询es里面的数据,今天我教大家一个简单的es的查询.废话不多说,直接上代码. 在pom文件中引入 <dependency> ...

  4. RTC+AI|“即智”数智人创新内容生产体验,为企业降本增效再提速

    号称"史上最卷"的618年中大促落下帷幕,几大电商巨头在直播投入和短视频内容建设上持续加码,短视频+直播电商的营销模式成为618期间的主要输出. 以某美妆专场直播间为例,主播现场手 ...

  5. 【MAUI Blazor踩坑日记】3.Windows标题栏自定义颜色,运行时改变颜色

    目录 修改默认颜色 修改运行时颜色 效果图 MAUI中Windows默认的标题栏颜色是灰色的,有一点丑. 如果去掉默认的标题栏,自己画一个,可能会出现问题,也比较麻烦. 想要自定义默认标题栏的颜色,官 ...

  6. vlunhub笔记(一)deathnote

    (一)查询靶机ip 通过 arp-scan -l 查询目标靶机ip,查询结果如下图红框所示. (二)信息收集 直接访问目标ip,发现无法访问,只返回网站域名. 网站返回域名,就将该域名添加进hosts ...

  7. .Net Web API 004 Controller获取对象列表,传入数据以及对象

    1.返回UserEntityList 这个服务接口的目的是分为用户列表,代码如下所示. /// <summary> /// 得到用户列表 /// </summary> /// ...

  8. RedHat8静默安装was

    前言 was(websphere application server),类似weblogic.tomcat,由IBM开发的一种企业级Java容器. 系统版本:redhat 8.2 was版本:was ...

  9. dimp V8:[WARNING]login fail, check your username and password, and check the server status

    在进行某个项目的性能测试时,我们选择了达梦8作为使用的数据库.因前期的网络安全问题和考虑到节省成本,我们首先在公司本地服务器上搭建了相应的环境,并生成了用于压力测试的业务数据. 然而,在将数据库迁移到 ...

  10. go-zero 是如何实现计数器限流的?

    原文链接: 如何实现计数器限流? 上一篇文章 go-zero 是如何做路由管理的? 介绍了路由管理,这篇文章来说说限流,主要介绍计数器限流算法,具体的代码实现,我们还是来分析微服务框架 go-zero ...