C++---树形DP---树的最长路径(每日一道算法2023.5.4)

这篇具有很好参考价值的文章主要介绍了C++---树形DP---树的最长路径(每日一道算法2023.5.4)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

注意事项:
本题为"树与图的DFS深度优先遍历—树的重心"的近似题,同时涉及到 单链表模拟邻接表存储图 的操作,建议先理解那篇文章。

题目:
给定一棵树,树中包含 n 个结点(编号1~n)和 n−1 条无向边,每条边都有一个权值。
现在请你找到树中的一条最长路径。
换句话说,要找到一条路径,使得使得路径两端的点的距离最远。
注意:路径中可以只包含一个点。

输入格式
第一行包含整数 n。
接下来 n−1 行,每行包含三个整数 ai,bi,ci,表示点 ai 和 bi 之间存在一条权值为 ci 的边。

输出格式
输出一个整数,表示树的最长路径的长度。

数据范围
1≤n≤10000,
1≤ai,bi≤n,
−1e5≤ci≤1e5

输入:
6
5 1 6
1 4 5
6 3 9
2 6 8
6 1 7
输出:
22
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
using namespace std;

const int N = 10010, M = N*2;
int n, ans;                              //ans存储最终答案
int h[N], e[M], ne[M], w[M], idx = 0;     //单链表模拟邻接表

//邻接表增加一条边
void add(int a, int b, int c) {
    e[idx] = b;
    ne[idx] = h[a];
    w[idx] = c;
    h[a] = idx++;
}

//dfs数位dp,u是当前节点,f是当前节点的上一个节点(父节点)
int dfs(int u, int f) {
    int dist = 0;  //从当前点往下走的最大长度
    int d1 = 0, d2 = 0;   //表示挂在当前点上的最长路径d1和次长距离d2

    //枚举当前点i能到达的所有子节点j(遍历单链表)
    for (int i = h[u]; i!=-1; i=ne[i]) {
        int j = e[i];
        if (j == f) continue;   //由于是无向边,从a到b和从b到a都能走,但我们希望只能向下走,所以不能走回父节点

        int d = dfs(j, u) + w[i];   //子节点j往下走的最大长度 + j到i的边权
        dist = max(dist, d);

        //两种情况: 1.如果d大于等于d1,原本的最长路径就变为了次长路径,再把d存为最长路径 / 2.如果d不大于d1,但大于d2,直接更新即可
        if (d >= d1) {d2 = d1, d1 = d;}
        else if (d > d2) {d2 = d;}
    }

    ans = max(ans, d1+d2);    //d1+d2得到的就是穿过当前这个点的最长路径,因为一条最长向下的路 + 一条次长向下的路,合起来就是最长的路
    return dist;
}

int main() {
    //读入
    cin >> n;
    memset(h, -1, sizeof h);  //所有链头都指向-1即可
    for (int i = 0; i<n-1; i++) {  //n-1条无向边
        int a, b, c;
        cin >> a >> b >> c;
        add(a, b, c); add(b, a, c);
    }

    dfs(1, -1);     //初始父节点随便设个不存在的就行
    cout << ans;

    return 0;
}

思路:
整体的思路不算难,首先,树可以被"拎起来",也就是可以随意挑一个点为根节点,
剩下的点都向下延申 (大家都见过二叉树吧?长得差不多,只不过可以有多个子节点)。

可以通过dfs来枚举所有路径的"最高"节点,假设当前路径为1-2-3,最高节点是2,
如何找到最高点为2的所有路径中的最长路径?
就是找到所有从节点2往下延申的路径中最长的那条和次长的那条,加起来即为答案,
dfs返回的是当前节点向下延申的最长路径,这样如果有多个子节点,就可以直接比较dfs+w[i,j]的返回结果即可。
C++---树形DP---树的最长路径(每日一道算法2023.5.4)

还有更新最长和次长路径时会遇到的情况:
1.如果新的路径d大于等于d1,原本的最长路径就变为了次长路径,再把d存为最长路径
2.如果d不大于d1,但大于d2,直接更新即可

如果有所帮助请给个免费的赞吧~有人看才是支撑我写下去的动力!

声明:
算法思路来源为y总,详细请见https://www.acwing.com/
本文仅用作学习记录和交流文章来源地址https://www.toymoban.com/news/detail-433780.html

到了这里,关于C++---树形DP---树的最长路径(每日一道算法2023.5.4)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • C++---快速选择(每日一道算法2023.4.8)

    注意事项: 快速排序的一个拓展算法,建议先了解快排:快速排序—前后双指针法 题目: 给一个未排序的数列,列表中不包含重复元素,要求找到第k大的元素并输出。 输入格式 第一行两个整数,n,k,用空格隔开,分别表示序列长度和需要找到第k大的元素。 第二行有n个

    2023年04月12日
    浏览(22)
  • C++---背包模型---潜水员(每日一道算法2023.3.13)

    注意事项: 本题是\\\"动态规划—01背包\\\"和\\\"背包模型—二维费用的背包问题\\\"的扩展题,优化思路不多赘述,dp思路会稍有不同,下面详细讲解。 题目: 潜水员为了潜水要使用特殊的装备。 他有一个带2种气体的气缸:一个为氧气,一个为氮气。 让潜水员下潜的深度需要各种数

    2024年02月09日
    浏览(22)
  • 算法套路十九——树形DP

    树形 DP,即在树上进行的 DP。由于树固有的递归性质,这里的DP是指是一种通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法,故虽然带有DP,但一般都是通过 递归 来进行。 给定一棵二叉树,你需要计算它的直径长度。一棵二叉树的直径长度是任意两个结点路

    2024年02月10日
    浏览(78)
  • 2023 CCPC 华为云计算挑战赛 hdu7401 流量监控(树形dp)

    题目 流量监控 - HDU 7401 - Virtual Judge 简单来说,T(T=20)组样例,sumn不超过2e4 每次给定一棵n(n=2000)个点的树,两问: ①将n个点恰拆成n/2个pair(u,v),要求一个点是另一个点的祖先,求方案数 ②若两个pair(u,v)、(w,x)满足: u是v、w、x的祖先,w是v、x的祖先,v是x的祖先 即,四个点都

    2024年02月12日
    浏览(23)
  • 每日一题 1372二叉树中的最长交错路径

    给你一棵以  root  为根的二叉树,二叉树中的交错路径定义如下: 选择二叉树中  任意  节点和一个方向(左或者右)。 如果前进方向为右,那么移动到当前节点的的右子节点,否则移动到它的左子节点。 改变前进方向:左变右或者右变左。 重复第二步和第三步,直到你

    2024年02月10日
    浏览(30)
  • 每日一道算法题 1

    借鉴文章:Java-敏感字段加密 - 哔哩哔哩 题目描述  给定一个由多个命令字组成的命令字符串; 1、字符串长度小于等于127字节,只包含大小写字母,数字,下划线和偶数个双引号 2、命令字之间以一个或多个下划线_进行分割 3、可以通过两个双引号\\\"\\\"来标识包含下划线_的命令

    2024年02月04日
    浏览(26)
  • acwing算法基础之动态规划--数位统计DP、状态压缩DP、树形DP和记忆化搜索

    暂无。。。 暂无。。。 题目1 :求a~b中数字0、数字1、…、数字9出现的次数。 思路:先计算1~a中每位数字出现的次数,然后计算1~b-1中每位数字出现的次数,两个相减即是最终答案。 那么,如何计算1~a中每位数字出现的次数呢? 首先,将a的每一位存入向量num中,例如a=123

    2024年02月04日
    浏览(36)
  • 算法基础复盘笔记Day11【动态规划】—— 区间DP、计数类DP、树形DP、记忆化搜索

    ❤ 作者主页:欢迎来到我的技术博客😎 ❀ 个人介绍:大家好,本人热衷于 Java后端开发 ,欢迎来交流学习哦!( ̄▽ ̄)~* 🍊 如果文章对您有帮助,记得 关注 、 点赞 、 收藏 、 评论 ⭐️⭐️⭐️ 📣 您的支持将是我创作的动力,让我们一起加油进步吧!!!🎉🎉 1. 题目

    2024年02月01日
    浏览(31)
  • AcWing算法学习笔记:动态规划(背包 + 线性dp + 区间dp + 计数dp + 状态压缩dp + 树形dp + 记忆化搜索)

    算法 复杂度 时间复杂度0(nm) 空间复杂度0(nv) 代码 算法 通过滚动数组对01背包朴素版进行空间上的优化 f[i] 与 f[i - 1]轮流交替 若体积从小到大进行遍历,当更新f[i, j]时,f[i - 1, j - vi] 已经在更新f[i, j - vi]时被更新了 因此体积需要从大到小进行遍历,当更新f[i, j]时,f[i - 1,

    2024年02月21日
    浏览(34)
  • 【算法】树形DP ② 打家劫舍Ⅲ(树上最大独立集)

    最大独立集 需要从图中选择尽量多的点,使得这些点互不相邻。 337. 打家劫舍 III 用一个数组 int[] = {a, b} 来接收每个节点返回的结果 。返回值{a,b} a表示没选当前节点的最大值,b表示选了当前节点的最大值。 使用 后序遍历 dfs。 ( 发现树形 DP 基本都是后序 dfs ) P1352 没有上

    2024年02月12日
    浏览(31)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包