【算法竞赛】树上最长公共路径前缀(蓝桥杯2024真题·团建·超详细解析)

目录

一、题目

二、思路

1.  问题转化:同步DFS走树

2.  优化:同步DFS匹配

3.  状态设计:dfs参数含义

4.  匹配过程:用 map 建立权值索引

5.  终止条件:无法匹配则更新答案

6. 总结

 三、完整代码

四、知识点总结

1. 邻接表建树

 2. DFS模板(树)

3. map统计映射

 五、优化建议


一、题目

题目链接:蓝桥杯2024年第十五届省赛真题-团建 - C语言网
标签:树、DFS、映射、最长公共前缀

【题目抽象过来就是】:

  • 两棵树分别从根结点1出发

  • 每棵树走一条路径,从根走到叶子

  • 只要路径上对应位置的权值一致,前缀继续,直到不一致

  • 任意一对路径中最长的公共前缀长度

【等价描述】:

从树1的结点i和树2的结点j同时出发,若其子节点中存在相同权值的点,则同步走向下一个匹配点,继续搜索;否则终止,更新答案

二、思路

本质上就是是树上路径问题,目标是找出两棵树中一对路径,其权值前缀最长,且两个路径需从根走到某个叶子

1.  问题转化:同步DFS走树

我们将这个“团建”问题转化为更形式化的问题:

  • 设第一棵树为 T1​,第二棵树为 T2

  • 从T1的根结点(编号 1)出发,走到任意叶节点形成一个权值路径 P1

  • 从T2 的根结点(编号 1)出发,走到任意叶节点形成另一个权值路径 P2

  • 目标是找出一对路径 P1​, P2,使它们的最长公共前缀(权值完全相同)长度最大

这个问题很容易想到暴力做法,枚举所有从根到叶的路径组合,比较公共前缀,但这会非常低效,因为路径组合的数量是指数级的

2.  优化:同步DFS匹配

我们注意到只要两棵树当前所在的节点权值一致,就可以继续尝试向下匹配,于是我们可以设计一个双树同步DFS的过程:

  1. 从两棵树的根结点出发(必须权值相同才开始);

  2. 进入递归函数 dfs(i, j, pi, pj, cnt),表示当前在第一棵树的结点 i,第二棵树的结点 jpipj 是其父节点,用于避免走回头路;

  3. 当前的公共前缀长度为 cnt

  4. 然后尝试“配对子节点”:

    • i 的所有子节点(除了父节点)建立 map<int,int> 表(key=权值,value=结点编号);

    • 遍历 j 的所有子节点(同样跳过父节点),如果它的权值在上面的 map 中出现,说明两个子节点具有相同的权值;

    • 则递归调用 dfs(新i, 新j, i, j, cnt + 1),继续向下探索;

  5. 若当前无法继续匹配,说明一条公共前缀路径终止,更新 ans = max(ans, cnt)

这其实相当于构造了一个“公共路径树”:每次 DFS 都在尝试走向匹配路径的更深层

3.  状态设计:dfs参数含义

dfs(i, j, pi, pj, cnt)

  • i, j:当前分别在两棵树的哪个结点

  • pi, pj:各自结点的父结点,用于防止重复访问(因为树是无向图)

  • cnt:当前公共前缀的长度,也就是成功“匹配”的层数

每次进入 dfs,相当于说:“我已经找到了 cnt 层的共同路径,现在看看是否能进入下一层”

4.  匹配过程:用 map 建立权值索引

由于要找到第二棵树某个子节点的权值是否和第一棵树子节点的权值相同,为了快速判断和定位,我们用 map<int, int> 来做映射

map<int, int> m;
for (int newi : edge1[i]) {if (newi == pi) continue; //避免回头m[c[newi]] = newi; //权值 → 节点编号
}

然后对于 j 的所有子节点,判断它们的权值是否在 m 中出现:

for (int newj : edge2[j]) {if (newj == pj) continue;if (m.count(d[newj])) {//匹配成功,进入下一层dfs(m[d[newj]], newj, i, j, cnt + 1);}
}

这种方式效率高,而且灵活地实现了“同步匹配”的过程

5.  终止条件:无法匹配则更新答案

一旦某一层匹配失败(即 j 的子节点权值无法在 i 的子节点中找到对应值),这条同步路径就结束了,此时需要更新全局最大值:

ans = max(ans, cnt);

这句代码放在 DFS 末尾,保证所有路径尝试都会记录最长前缀

6. 总结

  • 我们不需要预先构造所有路径

  • 只需从根节点出发,通过匹配下一层的子节点权值,构造公共前缀路径(相当于剪枝)

  • 整个过程由 DFS 驱动,使用 mapunordered_map 快速匹配子结点

  • 最终输出最长的前缀长度 ans

 三、完整代码

#include <iostream>
#include <vector>
#include <map> 
using namespace std;
const int N=2e5+10;
int n,m;
int c[N];//第一棵树的权值
int d[N];//第二棵树的权值 
vector<vector<int>> edge1(N);//第一棵树邻接表,大小为N,存储的类型为vector 
vector<vector<int>> edge2(N);//第二棵树 
int ans=0;//i:第一棵树的当前节点
//j:第二棵树的当前节点 
//pi:当前结点的父结点
//pj:同理 
//cnt:当前前缀长度 
void dfs(int i,int j,int pi,int pj,int cnt)
{//存储第一棵树的相邻节点权值//first:权值,second:出现的次数 //map可以用来统计出现的次数 map<int,int>m; for(int newi:edge1[i]){//避免回头走,父结点跳过 if(newi==pi) continue;//记录权值对应位置 m[c[newi]]=newi;}//找第二棵树 for(int newj:edge2[j]){if(newj==pj) continue;//碰到相同权值点,继续向下走 //count统计的是次数 if(m.count(d[newj])){dfs(m[d[newj]],newj,i,j,cnt+1);}}//当前结点找不到相同权值,结束//更新答案ans=max(ans,cnt);return; 
}
int main()
{cin>>n>>m;for(int i=1;i<=n;i++) cin>>c[i];for(int i=1;i<=m;i++) cin>>d[i];for(int i=1;i<=n-1;i++){int x,y;cin>>x>>y;edge1[x].push_back(y);edge1[y].push_back(x);}for(int i=1;i<=m-1;i++){int x,y;cin>>x>>y;edge2[x].push_back(y);edge2[y].push_back(x);}//根节点相同才能进入dfs if(c[1]==d[1]) dfs(1,1,-1,-1,1);cout<<ans;return 0;
}

四、知识点总结

1. 邻接表建树

vector<vector<int>> tree(N);
tree[u].push_back(v);
tree[v].push_back(u); //因为是无向图建树

 2. DFS模板(树)

void dfs(int u, int parent) {for (int v : tree[u]) {if (v == parent) continue;dfs(v, u);}
}

3. map统计映射

map<int, int> m;
m[val] = index; //记录权值和对应结点编号

 五、优化建议

  • 如果运行时常数过大,可以用 unordered_map 替代 map 加快哈希效率

  • 若题目限制非常紧,也可以采用前缀哈希或 Trie 树进行路径存储优化

如果你觉得有收获,欢迎点赞收藏支持!
后续将持续更新算法题解,也欢迎留言交流~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/75222.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

开源免费虚拟化平台PVE软件定义网络

一、PVE SDN&#xff08;Software Defined Networking&#xff09;原理与使用逻辑 SDN&#xff08;软件定义网络&#xff09; 是一种将网络控制逻辑从传统交换机、路由器中分离出来的技术&#xff0c;使得网络可以通过软件集中管理和自动化配置。 Proxmox VE&#xff08;PVE&…

mysql 8.0.41下载安装教程(附安装包)mysql 8.0.41图文详细安装教程

文章目录 前言一、mysql 8.0.41 简介二、安装前准备三、MySQL 8.0 安装流程解析1.解压安装包2.启动安装程序3.选择安装类型4.选择安装组件5.开始安装6.配置设置&#xff08;部分步骤&#xff09;7.设置数据库密码8.完成安装配置9.配置环境变量&#xff1a;10.验证安装&#xff…

JAVA基础八股复习

1.局部变量一般存放在栈中&#xff0c;成员变量一般存放在堆中 2.什么是多态&#xff1f;谈谈对多态的理解&#xff1f; 在面向对象语言中&#xff0c;接口的多种不同的实现方式即为多态。用白话来说&#xff0c;就是多个对象调用同一个方法&#xff0c;得到不同的结果。 多态中…

10:00开始面试,10:08就出来了,问的问题有点变态。。。

从小厂出来&#xff0c;没想到在另一家公司又寄了。 到这家公司开始上班&#xff0c;加班是每天必不可少的&#xff0c;看在钱给的比较多的份上&#xff0c;就不太计较了。没想到8月一纸通知&#xff0c;所有人不准加班&#xff0c;加班费不仅没有了&#xff0c;薪资还要降40%…

k8s核心资源对象一(入门到精通)

本文将深入探讨Kubernetes中的核心资源对象&#xff0c;包括Pod、Deployment、Service、Ingress、ConfigMap和Secret&#xff0c;详细解析其概念、功能以及实际应用场景&#xff0c;帮助读者全面掌握这些关键组件的使用方法。 一、pod 1 pod概念 k8s最小调度单元&#xff0c;…

《Sqoop 快速上手:安装 + 测试实战》

推荐原文 见&#xff1a;http://docs.xupengboo.top/bigdata/di/sqoop.html Sqoop&#xff08;SQL-to-Hadoop&#xff09; 是 Apache 开源的工具&#xff0c;专门用于在 Hadoop 生态系统&#xff08;如 HDFS、Hive、HBase&#xff09; 和 关系型数据库&#xff08;如 MySQL、O…

数据结构刷题之贪心算法

贪心算法&#xff08;Greedy Algorithm&#xff09; 是一种在每个步骤中都选择当前最优解的算法设计策略。它通常用于解决优化问题&#xff0c;例如最小化成本或最大化收益。贪心算法的核心思想是&#xff1a;在每一步选择中&#xff0c;都做出局部最优的选择&#xff0c;希望…

重新定义PPT创作!ChatPPT发布全球首个AI PPT专用MCP Server

在这个AI技术日新月异的时代&#xff0c;ChatPPT团队推出革命性的MCP Server&#xff08;Multimodal Collaboration Platform&#xff09;&#xff0c;这是全球首个专注于AI PPT生成领域的智能协作平台。该平台的诞生&#xff0c;标志着PPT创作正式迈入"智能协作"新纪…

未来蓉城:科技与生态共舞的诗意栖居-成都

故事背景 故事发生在中国四川成都的2075年&#xff0c;展现科技与自然深度交融的未来城市图景。通过六个充满想象力的生态装置场景&#xff0c;描绘市民在智慧城市中诗意栖居的生活状态&#xff0c;展现环境保护与人文传承的和谐共生。 故事内容 在电子竹林轻轨站&#xff0c;通…

计算机网络笔记-分组交换网中的时延

一、分组交换网络中的四种时延类型 1. 排队时延 在队列中&#xff0c;当分组在链路上等着被传输时的时延为排队时延&#xff0c;一个分组的排队时延长度取决于该分组前方等待传输的分组数量&#xff0c;如果排队队列为空&#xff0c;且没有正在传输的分组那么该分组的排队时延…

ubuntu20.04.6LTS 安装PCL 1.9.1

在虚拟机中&#xff0c;ubuntu20.04.6 LTS 安装PCL 1.9.1&#xff0c;实测成功了。 注意&#xff1a; 1、编译时选择双核&#xff0c;否则编译到一半报错&#xff0c;因为内存不够进程被杀死。 虚拟机是4核心、内存8G。可能选3核更快一点&#xff0c;双核编译了2个多小时。 …

SQL:JOIN 完全指南:从基础到实战应用

JOIN 是 SQL 中最重要也最常用的操作之一&#xff0c;它允许我们从多个表中获取关联数据。本文将全面解析 SQL 中的各种 JOIN 类型&#xff0c;包括 INNER JOIN、LEFT JOIN、RIGHT JOIN、FULL JOIN 以及 CROSS JOIN&#xff0c;并通过实际示例展示它们的应用场景。 一、JOIN 基…

IDEA 2024 Maven 设置为全局本地仓库,避免新建项目重新配置maven

使用idea创建Java项目时每次都要重新配置Maven&#xff0c;非常麻烦。其实IDEA可以配置全局Maven。方法如下&#xff1a; 1.关闭所有项目进入初始页面 2.选择所有配置 3.设置为自己的路径

UDP怎么样实现可靠传输?

如果需要在基于UDP的应用中实现可靠传输&#xff08;例如确保数据不丢失、按顺序到达等&#xff09;&#xff0c;通常需要在应用层实现相应的机制。 1. 确认应答机制 应用层可以使用确认应答机制来确保数据的可靠传输。当发送方发送一个数据包时&#xff0c;接收方收到数据包…

【CSS基础】- 02(emmet语法、复合选择器、显示模式、背景标签)

css第二天 一、emmet语法 1、简介 ​ Emmet语法的前身是Zen coding,它使用缩写,来提高html/css的编写速度, Vscode内部已经集成该语法。 ​ 快速生成HTML结构语法 ​ 快速生成CSS样式语法 2、快速生成HTML结构语法 生成标签 直接输入标签名 按tab键即可 比如 div 然后tab…

每日算法:洛谷U535992 J-C 小梦的宝石收集(双指针、二分)

题目描述 小梦有 n 颗能量宝石&#xff0c;其中第 i 颗的能量为 ai​&#xff0c;但这些能量宝石十分不稳定&#xff0c;随时有可能发生崩坏&#xff0c;导致他们全部消失&#xff01; 小梦想要留住宝石们&#xff0c;不希望他们发生崩坏&#xff0c;同时他发现&#xff1a;如…

Spring MVC 逻辑视图(JSP、Thymeleaf、FreeMarker)与非逻辑视图(JSON、Excel、PDF、XML)详解及示例

Spring MVC 逻辑视图与非逻辑视图详解及示例 一、逻辑视图与非逻辑视图的定义 类型定义逻辑视图通过视图解析器&#xff08;ViewResolver&#xff09;将逻辑名称&#xff08;如 success&#xff09;映射到具体视图实现。非逻辑视图直接返回具体视图对象&#xff08;如 JsonVie…

【AAOS】【源码分析】CarAudioService(二)-- 功能介绍

汽车音频是 Android 汽车操作系统 (AAOS) 的一项功能,允许车辆播放信息娱乐声音,例如媒体、导航和通信。AAOS 不负责具有严格可用性和时间要求的铃声和警告,因为这些声音通常由车辆的硬件处理。将汽车音频服务集成在汽车中,彻底改变了驾驶体验,为驾驶员和乘客提供了音乐、…

docker安装软件汇总(持续更新)

1、简介 本文介绍一些常用的软件通过docker安装并启动&#xff0c;持续更新。 2、docker安装软件 2.1、zookeeper & kafka # 1、拉取zookeeper镜像 git pull wurstmeister/zookeeper # 2、启动zookeeper容器 docker run -d --restartalways --log-driver json-file --lo…

MySQL的左连接、右连接、内连接、外连接

一、前言 MySQL中的左连接、右连接、内连接和全外连接是用于多表关联查询的核心操作。 二、内连接&#xff08;INNER JOIN&#xff09; 定义&#xff1a;返回两个表中完全匹配的行&#xff0c;即只保留两个表连接字段值相等的行。示例场景&#xff1a;查询所有有选课记录的学…