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

news2025/4/19 1:55:35

目录

一、题目

二、思路

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.coloradmin.cn/o/2332717.html

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

相关文章

【windows10】基于SSH反向隧道公网ip端口实现远程桌面

【windows10】基于SSH反向隧道公网ip端口实现远程桌面 1.背景2.SSH反向隧道3.远程连接电脑 1.背景 ‌Windows 10远程桌面协议的简称是RDP&#xff08;Remote Desktop Protocol&#xff09;‌。 RDP是一种网络协议&#xff0c;允许用户远程访问和操作另一台计算机。 远程桌面功…

Python----概率论与统计(贝叶斯,朴素贝叶斯 )

一、贝叶斯 1.1、贝叶斯定理 贝叶斯定理&#xff08;Bayes Theorem&#xff09;也称贝叶斯公式&#xff0c;是关于随机事件的条件概率的定理 贝叶斯的的作用&#xff1a;根据已知的概率来更新事件的概率。 1.2、定理内容 提示&#xff1a; 贝叶斯定理是“由果溯因”的推断&…

爬虫抓包工具和PyExeJs模块

我们在处理一些网站的时候, 会遇到一些屏蔽F12, 以及只要按出浏览器的开发者工具就会关闭甚至死机的现象. 在遇到这类网站的时候. 我们可以使用抓包工具把页面上屏蔽开发者工具的代码给干掉. Fiddler和Charles 这两款工具是非常优秀的抓包工具. 他们可以监听到我们计算机上所…

无人机击落技术难点与要点分析!

一、技术难点 1. 目标探测与识别 小型化和低空飞行&#xff1a;现代无人机体积小、飞行高度低&#xff08;尤其在城市或复杂地形中&#xff09;&#xff0c;雷达和光学传感器难以有效探测。 隐身技术&#xff1a;部分高端无人机采用吸波材料或低可探测设计&#xff0c;进…

8.第二阶段x64游戏实战-string类

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 本次游戏没法给 内容参考于&#xff1a;微尘网络安全 上一个内容&#xff1a;7.第二阶段x64游戏实战-分析人物属性 string类是字符串类&#xff0c;在计算机中…

Go语言sync.Mutex包源码解读

互斥锁sync.Mutex是在并发程序中对共享资源进行访问控制的主要手段&#xff0c;对此Go语言提供了非常简单易用的机制。sync.Mutex为结构体类型&#xff0c;对外暴露Lock()、Unlock()、TryLock()三种方法&#xff0c;分别用于阻塞加锁、解锁、非阻塞加锁操作&#xff08;加锁失败…

C++实现文件断点续传:原理剖析与实战指南

文件传输示意图 一、断点续传的核心价值 1.1 大文件传输的痛点分析 网络闪断导致重复传输&#xff1a;平均重试3-5次。 传输进度不可回溯&#xff1a;用户无法查看历史进度。 带宽利用率低下&#xff1a;每次中断需从头开始。 1.2 断点续传技术优势 指标传统传输断点续传…

Python贝叶斯回归、强化学习分析医疗健康数据拟合截断删失数据与参数估计3实例

全文链接&#xff1a;https://tecdat.cn/?p41391 在当今数据驱动的时代&#xff0c;数据科学家面临着处理各种复杂数据和构建有效模型的挑战。本专题合集聚焦于有序分类变量处理、截断与删失数据回归分析以及强化学习模型拟合等多个重要且具有挑战性的数据分析场景&#xff0c…

微信小程序 -- 原生封装table

文章目录 table.wxmltable.wxss注意 table.js注意 结果数据结构 最近菜鸟做微信小程序的一个查询功能&#xff0c;需要展示excel里面的数据&#xff0c;但是菜鸟找了一圈&#xff0c;也没发现什么组件库有table&#xff0c;毕竟手机端好像确实不太适合做table&#xff01; 菜鸟…

分布式文件存储系统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构建&#xff0c;其服务端数据验证采用Jakarta Validation API​&#xff08;原JSR 380规范&#xff09;&#xff0c;通过声明式注解与自定义扩展机制实现高效、灵活的数据校验体系。以下从技术实现、核心能力、场景优化三个维度展开解析&#…

学透Spring Boot — 017. 魔术师—Http消息转换器

本文是我的专栏《学透Spring Boot》的第17篇文章&#xff0c;了解更多请移步我的专栏&#xff1a; 学透 Spring Boot_postnull咖啡的博客-CSDN博客 目录 HTTP请求和响应 需求—新的Media Type 实现—新的Media Type 定义转换器 注册转换器 编写Controller 测试新的medi…

BOE(京东方)旗下控股子公司“京东方能源”成功挂牌新三板 以科技赋能零碳未来

2025年4月8日,BOE(京东方)旗下控股子公司京东方能源科技股份有限公司(以下简称“京东方能源”)正式通过全国中小企业股份转让系统审核,成功在新三板挂牌(证券简称:能源科技,证券代码:874526),成为BOE(京东方)自物联网转型以来首个独立孵化并成功挂牌的子公司。此次挂牌是BOE(京…

Git使用与管理

一.基本操作 1.创建本地仓库 在对应文件目录下进行&#xff1a; git init 输入完上面的代码&#xff0c;所在文件目录下就会多一个名为 .git 的隐藏文件&#xff0c;该文件是Git用来跟踪和管理仓库的。 我们可以使用 tree 命令&#xff08;注意要先下载tree插件&#xff09…

计算机网络——传输层(Udp)

udp UDP&#xff08;User Datagram Protocol&#xff0c;用户数据报协议 &#xff09;是一种无连接的传输层协议&#xff0c;它在IP协议&#xff08;互联网协议&#xff09;之上工作&#xff0c;为应用程序提供了一种发送和接收数据报的基本方式。以下是UDP原理的详细解释&…

图解Java设计模式

1、设计模式面试题 2、设计模式的重要性 3、7大设计原则介绍 3.1、单一职责原则

wsl2+ubuntu22.04安装blender教程(详细教程)

本章教程介绍,如何在Windows操作系统上通过wsl2+ubuntu安装blender并运行教程。Blender 是一款免费、开源的 ​​3D 创作套件​​,广泛应用于建模、动画、渲染、视频编辑、特效制作等领域。它由全球开发者社区共同维护,支持跨平台(Windows、macOS、Linux),功能强大且完全…

Spring AI Alibaba MCP 市场正式上线!

Spring AI Alibaba 正式上线 MCP 市场&#xff1a;Spring AI Alibaba-阿里云Spring AI Alibaba官网官网。 开发者可以在这里搜索市面上可用的 MCP Server 服务&#xff0c;了解每个服务的实现与接入方法。 MCP 市场是做什么的&#xff1f; Spring AI Alibaba MCP 当前主要提供…

【Hadoop入门】Hadoop生态圈概述:核心组件与应用场景概述

1 Hadoop生态圈概述 Hadoop生态圈是以 HDFS&#xff08;分布式存储&#xff09; 和 YARN&#xff08;资源调度&#xff09; 为核心&#xff0c;围绕大数据存储、计算、管理、分析等需求发展出的一系列开源工具集合。 核心特点&#xff1a; 模块化&#xff1a;各组件专注解决特定…

致远OA —— 表单数据获取(前端)

文章目录 :apple: 业务需求描述 &#x1f34e; 业务需求描述 测试案例&#xff1a; https://pan.quark.cn/s/3f58972f0a27 官网地址&#xff1a; https://open.seeyoncloud.com/v5devCAP/94/355/359/399/405/406.html 需求描述&#xff1a; 点击获取数据接口&#xff0c;…