深度优先搜索+动态规划
题目链接:最小化旅行的价格总和
深度优先搜索
为了使旅行的价格总和最小,那么每次旅行的路径必定是最短路径。
每次旅行trips[i]
都是独立的,所以可以采用count[]
来记录,所有旅行中每个节点的访问次数
。
最短路径可以采用深度优先搜索。
TIP:获取所有的节点的访问次数后,总价格为:
priceTotal = Σ price[node] * count[node]
树形DP
以节点0
为树的根节点
状态表示:
f[node][0]
:以node
为根节点的子树,node
节点价格不变时,整个子树的最小价格f[node][1]
:以node
为根节点的子树,node
节点价格减半时,整个子树的最小价格
状态计算:
f[node][0] = Σ min(f[child][0], f[child][1])
:当前节点价格不变,孩子可以 减半/不变f[node][1] = Σ f[child][0]
:当前价格减半,孩子只能 不变
答案
min(f[0][0], f[0][1])
:以节点0
为树的根节点,priceTotal = Σ price[node] * count[node]
的最小值
func minimumTotalPrice(n int, edges [][]int, price []int, trips [][]int) int {
var (
g [][]int // 邻接表
count []int // 最短路径中,每个节点的访问次数
f [][]int // 动态规划
)
g = make([][]int, n)
count = make([]int, n)
f = make([][]int, n)
for i := 0; i < n; i++ {
g[i] = make([]int, 0)
f[i] = make([]int, 2)
}
for _, e := range edges {
g[e[0]] = append(g[e[0]], e[1])
g[e[1]] = append(g[e[1]], e[0])
}
var dfs func(cur, fa, end int) bool
dfs = func(cur, fa, end int) bool {
// 返回当前节点能否递归到终点
if cur == end {
count[cur]++
return true
}
for _, child := range g[cur] {
if child == fa {
continue
}
if dfs(child, cur, end) {
count[cur]++
return true
}
}
return false
}
for _, t := range trips {
dfs(t[0], -1, t[1])
}
var dp func(cur, fa int)
dp = func(cur, fa int) {
f[cur][0] = price[cur] * count[cur]
f[cur][1] = price[cur] / 2 * count[cur]
for _, child := range g[cur] {
if child == fa {
continue
}
dp(child, cur)
f[cur][0] += min(f[child][0], f[child][1])
f[cur][1] += f[child][0]
}
}
dp(0, -1)
return min(f[0][0], f[0][1])
}
func min(x, y int) int {
if x < y {
return x
}
return y
}