Blage's Coding Blage's Coding
Home
算法
  • 手写Spring
  • SSM
  • SpringBoot
  • JavaWeb
  • JAVA基础
  • 容器
  • Netty

    • IO模型
    • Netty初级
    • Netty原理
  • JVM
  • JUC
  • Redis基础
  • 源码分析
  • 实战应用
  • 单机缓存
  • MySQL

    • 基础部分
    • 实战与处理方案
    • 面试
  • ORM框架

    • Mybatis
    • Mybatis_Plus
  • SpringCloudAlibaba
  • MQ消息队列
  • Nginx
  • Elasticsearch
  • Gateway
  • Xxl-job
  • Feign
  • Eureka
  • 面试
  • 工具
  • 项目
  • 关于
🌏本站
🧸GitHub (opens new window)
Home
算法
  • 手写Spring
  • SSM
  • SpringBoot
  • JavaWeb
  • JAVA基础
  • 容器
  • Netty

    • IO模型
    • Netty初级
    • Netty原理
  • JVM
  • JUC
  • Redis基础
  • 源码分析
  • 实战应用
  • 单机缓存
  • MySQL

    • 基础部分
    • 实战与处理方案
    • 面试
  • ORM框架

    • Mybatis
    • Mybatis_Plus
  • SpringCloudAlibaba
  • MQ消息队列
  • Nginx
  • Elasticsearch
  • Gateway
  • Xxl-job
  • Feign
  • Eureka
  • 面试
  • 工具
  • 项目
  • 关于
🌏本站
🧸GitHub (opens new window)
  • 数组

  • 链表

  • 字符串

  • 二叉树

  • 动态规划

    • 5.最长回文子串
    • 72.编辑距离
    • 300.最长递增子序列
    • 1143.最长公共子序列
    • 239.滑动窗口最大值
    • 64.最小路径和
    • 718.最长重复子数组
    • 221.最大正方形
    • 198.打家劫舍
    • 152.乘积最大子数组
    • 1079.活字印刷
    • 139. 单词拆分
    • 6394. 字符串中的额外字符
    • 10. 正则表达式匹配
    • 1130. 叶值的最小代价生成树
    • 96. 不同的二叉搜索树
    • 279. 完全平方数
    • 416. 分割等和子集
    • 309. 最佳买卖股票时机含冷冻期
    • 312. 戳气球
    • 53. 最大子数组和
    • 1262. 可被三整除的最大和
    • 1186. 删除一次得到子数组最大和
    • 6912. 构造最长非递减子数组
    • 1911. 最大子序列交替和
    • 834. 树中距离之和
    • 343. 整数拆分
    • 123. 买卖股票的最佳时机 III
    • 115. 不同的子序列
    • 516. 最长回文子序列
    • 132. 分割回文串 II
    • 673. 最长递增子序列的个数
    • 2930. 重新排列后包含指定子字符串的字符串数目
    • 2646. 最小化旅行的价格总和
      • 1.深搜+树形dp
    • 剑指offer42
    • 剑指offer60
    • 剑指 Offer 49. 丑数
    • 背包问题

  • 深搜回溯

  • 数学贪心

  • 堆栈队列

  • 前缀和

  • 算法设计

  • 位运算

  • WA

  • 算法
  • 动态规划
phan
2023-12-06
目录

2646. 最小化旅行的价格总和

# 2646. 最小化旅行的价格总和 (opens new window)

# 1.深搜+树形dp

1、深搜:首先需要统计每次旅行中,经过的节点次数。因为是无根树,所以每次旅行的路径都是唯一的。

2、动态规划:每个节点上的总价值=节点经过的次数 x 当前节点的价值。节点如果一次没经过,则置为0。因此节点价值减半等效于节点的总价值减半,题目转化为打家劫舍Ⅲ场景的树形dp。

需要维护一个cache哈希表,记录当前节点不同状态下作为根所能得到的最小金额数量。

class Solution {
    Map<String, Integer> cache = new HashMap<>();
    public  int minimumTotalPrice(int n, int[][] edges, int[] price, int[][] trips) {
        List<Integer>[] g = new List[n];
        for (int i = 0; i < n; i++) {
            g[i] = new ArrayList<>();
        }
        for (int i = 0; i < edges.length; i++) {
            g[edges[i][0]].add(edges[i][1]);
            g[edges[i][1]].add(edges[i][0]);
        }
        int[] count = new int[n];
        //1.找出每条路径的经过的所有点数
        for (int i = 0; i < trips.length; i++) {
            boolean ans=dfs(g,count, -1,trips[i][0], trips[i][1]);
        }
        //2.动规求解路径减半
        for (int i = 0; i < count.length; i++) {
            count[i] = count[i] * price[i];
        }
        int res1=dp(g, count, -1,0, 1);
        int res2=dp(g, count, -1,0, -1);
        return Math.min(res1, res2);
    }
    private int dp(List<Integer>[] g, int[] count, int pre,int curr, int redu) {
        //redu:1表示当前节点减半 -1表示当前节点不减半
        int sum = redu==1?count[curr]/2:count[curr];
        String currKey = String.valueOf(curr) + "&" + String.valueOf(redu);
        for (Integer next : g[curr]) {
            String key1 = String.valueOf(next) + "&" + String.valueOf(1);
            String key2 = String.valueOf(next) + "&" + String.valueOf(-1);
            if (next != pre) {
                if (redu == 1) {
                    int tmp2 = cache.containsKey(key2) ? cache.get(key2) : dp(g, count, curr, next, -1);
                    sum+=tmp2;
                    cache.put(key2, tmp2);
                }
                else{
                    int tmp1 = cache.containsKey(key1) ? cache.get(key1) : dp(g, count, curr, next, 1);
                    int tmp2 = cache.containsKey(key2) ? cache.get(key2) : dp(g, count, curr, next, -1);
                    sum += Math.min(tmp1,tmp2);
                    cache.put(key1, tmp1);
                    cache.put(key2, tmp2);
                }
            }
        }
        cache.put(currKey, sum);
        return sum;
    }

    private boolean dfs(List<Integer>[] g, int[] count, int pre, int node, int target) {
        if (node == target) {
            count[target]++;
            return true;
        }
        boolean check = false;
        for (Integer next : g[node]) {
            if (next != pre) {
                boolean res = dfs(g, count, node, next, target);
                if(res) check = true;
            }
        }
        if (check) {
            count[node]++;
            return true;
        }
        return false;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
编辑 (opens new window)
#Leetcode#动态规划
上次更新: 2023/12/15, 15:49:57
2930. 重新排列后包含指定子字符串的字符串数目
剑指offer42

← 2930. 重新排列后包含指定子字符串的字符串数目 剑指offer42→

Theme by Vdoing | Copyright © 2023-2024 blageCoder
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式