【算法競賽】樹上最長公共路徑前綴(藍橋杯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.pswp.cn/web/75222.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/75222.shtml
英文地址,請注明出處:http://en.pswp.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;查詢所有有選課記錄的學…