【算法竞赛】树上最长公共路径前缀(蓝桥杯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的过程:
-
从两棵树的根结点出发(必须权值相同才开始);
-
进入递归函数
dfs(i, j, pi, pj, cnt),表示当前在第一棵树的结点i,第二棵树的结点j,pi、pj是其父节点,用于避免走回头路; -
当前的公共前缀长度为
cnt; -
然后尝试“配对子节点”:
-
对
i的所有子节点(除了父节点)建立map<int,int>表(key=权值,value=结点编号); -
遍历
j的所有子节点(同样跳过父节点),如果它的权值在上面的 map 中出现,说明两个子节点具有相同的权值; -
则递归调用
dfs(新i, 新j, i, j, cnt + 1),继续向下探索;
-
-
若当前无法继续匹配,说明一条公共前缀路径终止,更新
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 驱动,使用
map或unordered_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 树进行路径存储优化
如果你觉得有收获,欢迎点赞收藏支持!
后续将持续更新算法题解,也欢迎留言交流~
相关文章:
【算法竞赛】树上最长公共路径前缀(蓝桥杯2024真题·团建·超详细解析)
目录 一、题目 二、思路 1. 问题转化:同步DFS走树 2. 优化:同步DFS匹配 3. 状态设计:dfs参数含义 4. 匹配过程:用 map 建立权值索引 5. 终止条件:无法匹配则更新答案 6. 总结 三、完整代码 四、知识点总…...
【windows10】基于SSH反向隧道公网ip端口实现远程桌面
【windows10】基于SSH反向隧道公网ip端口实现远程桌面 1.背景2.SSH反向隧道3.远程连接电脑 1.背景 Windows 10远程桌面协议的简称是RDP(Remote Desktop Protocol)。 RDP是一种网络协议,允许用户远程访问和操作另一台计算机。 远程桌面功…...
Python----概率论与统计(贝叶斯,朴素贝叶斯 )
一、贝叶斯 1.1、贝叶斯定理 贝叶斯定理(Bayes Theorem)也称贝叶斯公式,是关于随机事件的条件概率的定理 贝叶斯的的作用:根据已知的概率来更新事件的概率。 1.2、定理内容 提示: 贝叶斯定理是“由果溯因”的推断&…...
NO.88十六届蓝桥杯备战|动态规划-多重背包|摆花(C++)
多重背包 多重背包问题有两种解法: 按照背包问题的常规分析⽅式,仿照完全背包,第三维枚举使⽤的个数;利⽤⼆进制可以表⽰⼀定范围内整数的性质,转化成01 背包问题。 ⼩建议:并不是所有的多重背包问题都能…...
vue项目打包里面pubilc里的 tinymce里的js文件问题
以下是解决 Vue 项目打包后 public/tinymce 中 JS 文件路径问题的完整方案: 问题原因 当使用 public 目录存放静态资源时,Vue CLI 默认会将 public 下的文件 直接复制到打包目录的根路径,但以下操作可能导致路径错误: 开发环境使…...
Python星球日记 - 第18天:小游戏开发(猜数字游戏)
🌟引言: 上一篇:Python星球日记 - 第17天:数据可视化 名人说:路漫漫其修远兮,吾将上下而求索。(屈原《离骚》) 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 目录 一、游戏概述与原理1. 游戏基本规则2. 编程知识点3.猜数字游戏流程图二、游戏逻辑设计…...
爬虫抓包工具和PyExeJs模块
我们在处理一些网站的时候, 会遇到一些屏蔽F12, 以及只要按出浏览器的开发者工具就会关闭甚至死机的现象. 在遇到这类网站的时候. 我们可以使用抓包工具把页面上屏蔽开发者工具的代码给干掉. Fiddler和Charles 这两款工具是非常优秀的抓包工具. 他们可以监听到我们计算机上所…...
无人机击落技术难点与要点分析!
一、技术难点 1. 目标探测与识别 小型化和低空飞行:现代无人机体积小、飞行高度低(尤其在城市或复杂地形中),雷达和光学传感器难以有效探测。 隐身技术:部分高端无人机采用吸波材料或低可探测设计,进…...
2025年Java无服务器架构实战:AWS Lambda与Spring Cloud Function深度整合
摘要 📝 本文深入探讨如何在2025年Java生态中实现AWS Lambda与Spring Cloud Function的无缝整合。我们将从基础概念讲起,逐步深入到实际部署、性能优化和最佳实践,通过详实的代码示例展示如何构建高效、可扩展的无服务器Java应用。 目录 &a…...
LeetCode 题目 「二叉树的右视图」 中,如何从「中间存储」到「一步到位」实现代码的优化?
背景简介 在 LeetCode 的经典题目 「二叉树的右视图」 中,我们需要返回从右侧看一棵二叉树时所能看到的节点集合。每一层我们只能看到最右边的那个节点。 最初,我采用了一个常规思路:层序遍历 每层单独保存节点值 最后提取每层最后一个节…...
8.第二阶段x64游戏实战-string类
免责声明:内容仅供学习参考,请合法利用知识,禁止进行违法犯罪活动! 本次游戏没法给 内容参考于:微尘网络安全 上一个内容:7.第二阶段x64游戏实战-分析人物属性 string类是字符串类,在计算机中…...
Go语言sync.Mutex包源码解读
互斥锁sync.Mutex是在并发程序中对共享资源进行访问控制的主要手段,对此Go语言提供了非常简单易用的机制。sync.Mutex为结构体类型,对外暴露Lock()、Unlock()、TryLock()三种方法,分别用于阻塞加锁、解锁、非阻塞加锁操作(加锁失败…...
C++实现文件断点续传:原理剖析与实战指南
文件传输示意图 一、断点续传的核心价值 1.1 大文件传输的痛点分析 网络闪断导致重复传输:平均重试3-5次。 传输进度不可回溯:用户无法查看历史进度。 带宽利用率低下:每次中断需从头开始。 1.2 断点续传技术优势 指标传统传输断点续传…...
MySQL中FIND_IN_SET函数与INSTR函数用法解析
一、功能定义与语法 1、FIND_IN_SET函数 语法:FIND_IN_SET(str, strlist) 功能:在逗号分隔的字符串列表(strlist)中查找精确匹配的子字符串(str),并返回其位置(从1开始)…...
Python贝叶斯回归、强化学习分析医疗健康数据拟合截断删失数据与参数估计3实例
全文链接:https://tecdat.cn/?p41391 在当今数据驱动的时代,数据科学家面临着处理各种复杂数据和构建有效模型的挑战。本专题合集聚焦于有序分类变量处理、截断与删失数据回归分析以及强化学习模型拟合等多个重要且具有挑战性的数据分析场景,…...
Git 协同开发的常用操作
1. 单仓库(多分支开发) 从远程拉取代码 git clone https://gitee.com/...查看当前分支 git branch -- *master创建并切换到你的开发分支(my-dev) git checkout -b my-dev查看当前分支 git branch -- marster -- *my-dev提交代…...
微信小程序 -- 原生封装table
文章目录 table.wxmltable.wxss注意 table.js注意 结果数据结构 最近菜鸟做微信小程序的一个查询功能,需要展示excel里面的数据,但是菜鸟找了一圈,也没发现什么组件库有table,毕竟手机端好像确实不太适合做table! 菜鸟…...
分布式文件存储系统FastDFS
文章目录 1 分布式文件存储1_分布式文件存储的由来2_常见的分布式存储框架 2 FastDFS介绍3 FastDFS安装1_拉取镜像文件2_构建Tracker服务3_构建Storage服务4_测试图片上传 4 客户端操作1_Fastdfs-java-client2_文件上传3_文件下载4_获取文件信息5_问题 5 SpringBoot整合 1 分布…...
ZKmall开源商城服务端验证:Jakarta Validation 详解
ZKmall开源商城基于Spring Boot 3构建,其服务端数据验证采用Jakarta Validation API(原JSR 380规范),通过声明式注解与自定义扩展机制实现高效、灵活的数据校验体系。以下从技术实现、核心能力、场景优化三个维度展开解析&#…...
深度分页及优化建议
深度分页的定义 深度分页是指在分页查询中,当用户请求非常靠后的页面时,数据库需要处理大量数据,导致查询性能显著下降的情况。例如,一个查询结果有 100 万条记录,而用户要查询第 999 页(每页 10 条记录&a…...
电网电能质量分析:原理、算法及实际应用
一、引言 在现代社会,电力供应的稳定性和可靠性对工业生产、社会生活的各个方面都至关重要。电能质量作为衡量电力系统供电能力的关键指标,其优劣直接影响到电力设备的运行效率、使用寿命以及生产过程的稳定性。随着电力系统规模的不断扩大,新…...
学透Spring Boot — 017. 魔术师—Http消息转换器
本文是我的专栏《学透Spring Boot》的第17篇文章,了解更多请移步我的专栏: 学透 Spring Boot_postnull咖啡的博客-CSDN博客 目录 HTTP请求和响应 需求—新的Media Type 实现—新的Media Type 定义转换器 注册转换器 编写Controller 测试新的medi…...
BOE(京东方)旗下控股子公司“京东方能源”成功挂牌新三板 以科技赋能零碳未来
2025年4月8日,BOE(京东方)旗下控股子公司京东方能源科技股份有限公司(以下简称“京东方能源”)正式通过全国中小企业股份转让系统审核,成功在新三板挂牌(证券简称:能源科技,证券代码:874526),成为BOE(京东方)自物联网转型以来首个独立孵化并成功挂牌的子公司。此次挂牌是BOE(京…...
Airflow集成Lark机器人
🥭1. 实现目标 🕐 通过自定义函数,实现Lark机器人告警功能 🕐 通过Lark机器人代替邮件数据的发送功能 🥭2.自定义函数实现 from airflow import DAG from airflow.operators.python_operator import PythonOperator from airflow.models import Variable import requ…...
Git使用与管理
一.基本操作 1.创建本地仓库 在对应文件目录下进行: git init 输入完上面的代码,所在文件目录下就会多一个名为 .git 的隐藏文件,该文件是Git用来跟踪和管理仓库的。 我们可以使用 tree 命令(注意要先下载tree插件)…...
计算机网络——传输层(Udp)
udp UDP(User Datagram Protocol,用户数据报协议 )是一种无连接的传输层协议,它在IP协议(互联网协议)之上工作,为应用程序提供了一种发送和接收数据报的基本方式。以下是UDP原理的详细解释&…...
网络安全小知识课堂(五)
病毒与蠕虫:你的电脑为何会 “生病” 和 “传染”? 引言 你是否见过这样的场景:电脑突然弹窗广告暴增,文件莫名消失,甚至整个公司网络集体瘫痪?这些症状背后,可能是 ** 病毒(Virus…...
图解Java设计模式
1、设计模式面试题 2、设计模式的重要性 3、7大设计原则介绍 3.1、单一职责原则...
wsl2+ubuntu22.04安装blender教程(详细教程)
本章教程介绍,如何在Windows操作系统上通过wsl2+ubuntu安装blender并运行教程。Blender 是一款免费、开源的 3D 创作套件,广泛应用于建模、动画、渲染、视频编辑、特效制作等领域。它由全球开发者社区共同维护,支持跨平台(Windows、macOS、Linux),功能强大且完全…...
其他合成方式介绍
在 SurfaceFlinger 的 Layer 处理逻辑中,除了常见的 Client Composition(GPU合成) 和 Device Composition(HWC合成),还存在一些特殊的合成方式,比如 Sideband、Solid Color 和 Display Decorati…...
