算法學習系列(六十一):樹形DP

目錄

  • 引言
  • 一、沒有上司的舞會
  • 二、樹的重心
  • 三、樹的最長路徑
  • 四、樹的中心

引言

關于這個樹形 D P DP DP 代碼其實都是那一套,核心還是在于思維上的難度,關鍵是這個思路你能不能想明白,想明白了就非常的簡單,因為代碼幾乎長得都差不多,就是某些地方的改變罷了。剛開始學還是很難的,尤其是這種東西還會跟一些其它的算法混在一起,就很討厭了,所以繼續加油吧!


一、沒有上司的舞會

標簽:動態規劃、樹形DP、狀態機模型

思路:這道題其實寫了很多遍了,就是定義一個狀態 f [ i ] [ j ] , ( j = 0 , 1 ) f[i][j],(j=0,1) f[i][j],(j=0,1) ,代表選/不選當前結點 i i i 的情況下,整個分支的最大值。那么狀態轉移方程為: f [ u ] [ 0 ] = f [ u ] [ 0 ] + ∑ m a x ( f [ j ] [ 0 ] , f [ j ] [ 1 ] ) f[u][0] = f[u][0] + \sum max(f[j][0],f[j][1]) f[u][0]=f[u][0]+max(f[j][0],f[j][1]) f [ u ] [ 1 ] = f [ u ] [ 1 ] + ∑ f [ j ] [ 0 ] f[u][1] = f[u][1] + \sum f[j][0] f[u][1]=f[u][1]+f[j][0] 然后就進行遞歸操作即可,本質上還是先遞歸到子節點,然后子節點推出根結點的一個過程。

題目描述:

Ural 大學有 N 名職員,編號為 1~N。他們的關系就像一棵以校長為根的樹,父節點就是子節點的直接上司。每個職員有一個快樂指數,用整數 Hi 給出,其中 1≤i≤N。現在要召開一場周年慶宴會,不過,沒有職員愿意和直接上司一起參會。在滿足這個條件的前提下,主辦方希望邀請一部分職員參會,使得所有參會職員的快樂指數總和最大,求這個最大值。輸入格式
第一行一個整數 N。接下來 N 行,第 i 行表示 i 號職員的快樂指數 Hi。接下來 N?1 行,每行輸入一對整數 L,K,表示 K 是 L 的直接上司。(注意一下,后一個數是前一個數的父節點,不要搞反)。輸出格式
輸出最大的快樂指數。數據范圍
1≤N≤6000,?128≤Hi≤127
輸入樣例:
7
1
1
1
1
1
1
1
1 3
2 3
6 4
7 4
4 5
3 5
輸出樣例:
5

示例代碼:

#include <bits/stdc++.h>using namespace std;typedef long long LL;
typedef pair<int,int> PII;
#define x first
#define y secondconst int N = 6010, M = N, INF = 0x3f3f3f3f;int n, m;
int w[N];
int h[N], e[M], ne[M], idx;
int f[N][2];
bool has_father[N];void add(int a, int b)
{e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}void dfs(int u)
{f[u][1] = w[u];for(int i = h[u]; i != -1; i = ne[i]){int j = e[i];dfs(j);f[u][0] += max(f[j][0], f[j][1]);f[u][1] += f[j][0];}
}int main()
{ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);memset(h, -1, sizeof h);cin >> n;for(int i = 1; i <= n; ++i) cin >> w[i];for(int i = 0; i < n - 1; ++i){int a, b; cin >> a >> b;add(b,a);has_father[a] = true;}int root = 1;while(has_father[root]) root++;dfs(root);cout << max(f[root][0], f[root][1]) << endl;return 0;
}

二、樹的重心

標簽:dfs、樹形DP

思路:雖然從代碼上感覺不出來這是個 D P DP DP ,但其實 D P DP DP 就是用一個狀態表示了很多的狀態就叫做 D P DP DP ,這道題就是用了一個 t t t 代表包括它在內的向下子樹的結點的個數,然后在每個結點中都可以求出這個值,然后求出最大的,然后向上的連通塊的個數拿總的結點數減去分支的總和即可,然后找出最小的最大值即可。這里值得注意的是,沒有告訴父子關系,所以我們得建無向邊,同時要防止向上遞歸回去,這里可以用兩種方式解決,第一種是在參數中傳一個參數,是該結點的父親節點,遍歷分支的時候判斷一下即可,第二種是用一個判重數組,訪問過就不訪問了,這兩種都可以。

題目描述:

給定一顆樹,樹中包含 n 個結點(編號 1~n)和 n?1 條無向邊。請你找到樹的重心,并輸出將重心刪除后,剩余各個連通塊中點數的最大值。重心定義:重心是指樹中的一個結點,如果將這個點刪除后,剩余各個連通塊中點數的最大值最小,那么這個節點被稱為樹的重心。輸入格式
第一行包含整數 n,表示樹的結點數。接下來 n?1 行,每行包含兩個整數 a 和 b,表示點 a 和點 b 之間存在一條邊。輸出格式
輸出一個整數 m,表示將重心刪除后,剩余各個連通塊中點數的最大值。數據范圍
1≤n≤105
輸入樣例
9
1 2
1 7
1 4
2 8
2 5
4 3
3 9
4 6
輸出樣例:
4

示例代碼:

#include <bits/stdc++.h>using namespace std;typedef long long LL;
typedef pair<int,int> PII;
#define x first
#define y secondconst int N = 1e5+10, M = N * 2, INF = 0x3f3f3f3f;int n, m;
int h[N], e[M], ne[M], idx;
bool st[N];
int ans = 2e9;void add(int a, int b)
{e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}int dfs(int u)
{st[u] = true;int sum = 1, size = 0;for(int i = h[u]; i != -1; i = ne[i]){int j = e[i];if(st[j]) continue;int t = dfs(j);sum += t;size = max(size, t);}size = max(size, n - sum);ans = min(ans, size);return sum;
}int main()
{ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);memset(h, -1, sizeof h);cin >> n;for(int i = 0; i < n - 1; ++i){int a, b; cin >> a >> b;add(a,b), add(b,a);}dfs(1);cout << ans << endl;return 0;
}

三、樹的最長路徑

標簽:樹的深度優先遍歷、DP、樹形DP、樹的直徑

思路:首先這道題要求的是樹的直徑,這道題跟 大臣的旅費 不同的是該題的權重不相同,且不為正整數。最初的想法就是求最長路,想著拿 s p f a spfa spfa 求,只要把判斷 d i s t dist dist 的條件變了就行了,但是發現不對,因為 s p f a spfa spfa 會重復經過一個點,這個直徑每個點只會經過一次,然后就是用 D i j k s t r a Dijkstra Dijkstra 求的話,好像它的性質也不適用于最長路,然后就只能用樹形 D P DP DP 來求了。然后就是整體的思路就是遞歸每一個點,遞歸的值為該點向下的最大值,然后我們求出每個點多個分支中的第一、第二大點的和,然后對每個點的值求最值就是所求的答案。之所以說這道題為樹形 D P DP DP ,還是因為這個 t t t 代表著是一個集合的一個最值,這是 D P DP DP 的核心。
注意的點:第一、第二大值初始化應為 0 0 0 ,因為代表著無邊,如果是負的,那就不選該邊,也比它大,所以這個值最小也是 0 0 0 ,代表著什么邊也不選。并且因為只能向下走,跟上道題不同的是,這次使用的是第二種的判斷方法。又因為不知道父子結點的關系,所以要建無向邊,防止不能遞歸所有的點。
在這里插入圖片描述

題目描述:

給定一棵樹,樹中包含 n 個結點(編號1~n)和 n?1 條無向邊,每條邊都有一個權值。現在請你找到樹中的一條最長路徑。換句話說,要找到一條路徑,使得使得路徑兩端的點的距離最遠。注意:路徑中可以只包含一個點。輸入格式
第一行包含整數 n。接下來 n?1 行,每行包含三個整數 ai,bi,ci,表示點 ai 和 bi 之間存在一條權值為 ci 的邊。輸出格式
輸出一個整數,表示樹的最長路徑的長度。數據范圍
1≤n≤10000,1≤ai,bi≤n,?105≤ci≤105
輸入樣例:
6
5 1 6
1 4 5
6 3 9
2 6 8
6 1 7
輸出樣例:
22

示例代碼:

#include <bits/stdc++.h>using namespace std;typedef long long LL;
typedef pair<int,int> PII;
#define x first
#define y secondconst int N = 1e4+10, M = N * 2, INF = 0x3f3f3f3f;int n, m;
int h[N], e[M], w[M], ne[M], idx;
int ans = -2e9;void add(int a, int b, int c)
{e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}int dfs(int u, int father)
{int d1 = 0, d2 = 0;  // 最次也是0,沒有路徑for(int i = h[u]; i != -1; i = ne[i]){int j = e[i];if(j == father) continue;int t = dfs(j,u) + w[i];if(t >= d1) d2 = d1, d1 = t;else if(t > d2) d2 = t;	} ans = max(ans, d1 + d2);return d1;
}int main()
{ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);memset(h, -1, sizeof h);cin >> n;for(int i = 0; i < n - 1; ++i){int a, b, c; cin >> a >> b >> c;add(a,b,c), add(b,a,c);	}	dfs(1,-1);cout << ans << endl;return 0;
}

四、樹的中心

標簽:樹的深度優先遍歷、DP、樹形DP、換根DP

思路:這道題其實跟上一道題非常的像,題目要求的就是所有結點到其它結點最近的最遠距離是多少,首先我們可以跟上一道題的思路一樣求出每個點向下走的最遠距離,可以用一個數組存起來,然后就是求其向上走的最遠距離了,然后兩個取最大值,最后每個點取最小的最大值即可。前一個就不說了,就是上一題的思路,然后是求向上走的最大距離,向上走的點要么繼續向上走,要么向下走,向上走就是用父結點來更新子結點,我覺得這時候的上和下就剛好反過來了,因為本來這個結點向下走和從父結點到子結點,然后子結點的向上走就是該連邊加上父節點向下走的距離或者是父節點向上走的距離,只不過如果父結點向下走的最長距離中的結點有子結點,那就用第二長邊即可,詳情見代碼。

題目描述:

給定一棵樹,樹中包含 n 個結點(編號1~n)和 n?1 條無向邊,每條邊都有一個權值。請你在樹中找到一個點,使得該點到樹中其他結點的最遠距離最近。輸入格式
第一行包含整數 n。接下來 n?1 行,每行包含三個整數 ai,bi,ci,表示點 ai 和 bi 之間存在一條權值為 ci 的邊。輸出格式
輸出一個整數,表示所求點到樹中其他結點的最遠距離。數據范圍
1≤n≤10000,1≤ai,bi≤n,1≤ci≤105
輸入樣例:
5 
2 1 1 
3 2 1 
4 3 1 
5 1 1
輸出樣例:
2

示例代碼:

#include <bits/stdc++.h>using namespace std;typedef long long LL;
typedef pair<int,int> PII;
#define x first
#define y secondconst int N = 1e4+10, M = N * 2, INF = 0x3f3f3f3f;int n, m;
int h[N], e[M], w[M], ne[M], idx;
int d1[N], d2[N], p1[N], up[N];
bool is_leaf[N];void add(int a, int b, int c)
{e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}int dfs_d(int u, int father)
{d1[u] = d2[u] = -INF;for(int i = h[u]; i != -1; i = ne[i]){int j = e[i];if(j == father) continue;int d = dfs_d(j,u) + w[i];if(d >= d1[u]){d2[u] = d1[u], d1[u] = d;p1[u] = j;}else if(d > d2[u]){d2[u] = d;}}if(d1[u] == -INF){d1[u] = d2[u] = 0;is_leaf[u] = true;}return d1[u];
}void dfs_u(int u, int father)
{for(int i = h[u]; i != -1; i = ne[i]){int j = e[i];if(j == father) continue;if(j == p1[u]) up[j] = max(up[u], d2[u]) + w[i];else up[j] = max(up[u], d1[u]) + w[i];dfs_u(j,u);}
}int main()
{ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);memset(h, -1, sizeof h);cin >> n;for(int i = 0; i < n - 1; ++i){int a, b, c; cin >> a >> b >> c;add(a,b,c), add(b,a,c);}dfs_d(1,-1);dfs_u(1,-1);int res = d1[1];for(int i = 2; i <= n; ++i){if(is_leaf[i]) res = min(res, up[i]);else res = min(res, max(d1[i], up[i]));}cout << res << endl;return 0;
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/12680.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/12680.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/12680.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

LLM應用-prompt提示:讓大模型總結生成思維導圖

第一步&#xff1a;大模型生成markdown思維導圖格式 例如&#xff1a;kimi 總結pdf文檔案例&#xff1a; 生成的markdown格式&#xff1a; # 知識圖譜的構建及應用 ## 一、知識圖譜的構建 ### 1. 數據采集 - 來源&#xff1a;結構化數據庫、半結構化網頁、非結構化文本 - 預處…

React useState 的調用規則與最佳實踐:為何不在條件語句內使用 useState

在React中&#xff0c;useState 的調用確實有一些特定的規則和最佳實踐 以下是為什么通常不推薦在 if 語句內調用 useState 的原因&#xff1a; 1、Hooks 規則&#xff1a; React Hooks 的規則之一是&#xff0c;你應該在函數組件的頂層調用它們&#xff0c;而不是在循環、條…

技術管理者如何建立權威?

很多技術管理者經常抱怨管理不好做&#xff0c;還是做技術容易&#xff0c;完全受自己控制。員工一點都不聽自己的&#xff0c;安排的工作拖拖拉拉&#xff0c;一點執行力都沒有。 不是管理難做&#xff0c;而是管理者沒有建立權威。如何建立權威&#xff0c;參考以下四點。 …

PCIE V3.0物理層協議學習筆記

一、說明 PCI-Express(peripheral component interconnect express)是一種高速串行計算機擴展總線標準&#xff0c;它原來的名稱為“3GIO”&#xff0c;是由英特爾在2001年提出的&#xff0c;旨在替代舊的PCI&#xff0c;PCI-X和AGP總線標準。 PCIe屬于高速串行點對點雙通道高…

8.11 矢量圖層線要素單一符號使用二

文章目錄 前言箭頭&#xff08;Arrow&#xff09;QGis設置線符號為箭頭(Arrow)二次開發代碼實現 總結 前言 本章介紹矢量圖層線要素單一符號中箭頭&#xff08;Arrow&#xff09;的使用說明&#xff1a;文章中的示例代碼均來自開源項目qgis_cpp_api_apps 箭頭&#xff08;Arr…

證照之星是什么軟件 證照之星哪個版本好用?證照之星支持哪些相機 證照之星XE免費版

許多人都需要使用證件照&#xff0c;為了滿足這一需求&#xff0c;人們會使用照相機、手機、電腦等工具進行拍攝。除此之外&#xff0c;市面上還存在專門的證件照拍攝軟件&#xff0c;比如證照之星。那么&#xff0c;各位小伙伴是否了解證照之星哪個版本好用&#xff0c;證照之…

如何利用3D可視化大屏提升信息展示效果?

老子云3D可視化平臺https://www.laozicloud.com/ 引言 在信息爆炸的時代&#xff0c;如何有效地傳達和展示信息成為了各行各業的一大挑戰。傳統的平面展示方式已經無法滿足人們對信息展示的需求&#xff0c;3D可視化大屏應運而生&#xff0c;成為了提升信息展示效果的利器。本…

會員管理系統應該具備哪些功能?

?會員管理系統應該具備一系列核心功能&#xff0c;以滿足企業在會員管理、營銷和客戶服務等方面的需求。 以下是一些關鍵的會員管理系統功能&#xff1a; 1、會員信息管理&#xff1a;這是會員管理系統的基本功能&#xff0c;包括會員注冊、信息錄入、修改和查詢等。系統應支…

URL入參出參請求頭可配置化

整體思路 通過spring的Spell表達式解析變量的參數值&#xff0c;參數名定義為${XXX},在解析參數值后&#xff0c;將${XXX}替換成#XXX以匹配Spell表達式。 核心實現類 package com.example.spring_boot_study.spring.spell;import cn.hutool.core.map.MapUtil; import cn.hut…

大模型相關內容的研究學習

大模型研究學習 1.大模型的“幻覺” 幻覺可以分為事實性幻覺和忠實性幻覺。 事實性幻覺&#xff0c;是指模型生成的內容與可驗證的現實世界事實不一致。 比如問模型“第一個在月球上行走的人是誰&#xff1f;”&#xff0c;模型回復“Charles Lindbergh在1951年月球先驅任務…

the7主題下載,探索WordPress主題的無限可能

在數字時代&#xff0c;一個出色的網站是任何企業或個人品牌的必備。但在這個競爭激烈的網絡世界中&#xff0c;如何讓您的網站脫穎而出&#xff1f;答案就是 the7 —— 一款專為創造獨特和視覺沖擊力強的網站而設計的 WordPress 主題。 1. 無限設計可能性 the7 以其獨特的設…

探索政務熱線24小時在線服務:提升政府服務效能與民眾滿意度

一. 引言 在信息化、網絡化日益深入的今天&#xff0c;政府服務的方式也在不斷地變革與創新。政務熱線系統作為政府與民眾溝通的重要橋梁&#xff0c;其重要性不言而喻。政務熱線不僅是政府傾聽民眾聲音、回應社會關切的重要渠道&#xff0c;更是推動政府服務向數字化、智能化…

代碼隨想錄Day40:Leetcode343、96

Leetcode343&#xff1a; 問題描述&#xff1a; 給定一個正整數 n &#xff0c;將其拆分為 k 個 正整數 的和&#xff08; k > 2 &#xff09;&#xff0c;并使這些整數的乘積最大化。 返回 你可以獲得的最大乘積 。 代碼及注釋解析&#xff1a; class Solution { publ…

Linux-CentOS-7忘記密碼-修改登錄密碼圖文詳解

Linux-CentOS-7忘記密碼-修改登錄密碼圖文詳解 1.重啟系統&#xff1a; 在登錄界面&#xff0c;選擇要登錄的用戶并點擊"Power"按鈕&#xff0c;然后選擇"Restart"或"Reboot"重新啟動系統。 在系統啟動時持續按下 “e” 鍵進入編輯模式。 2…

谷歌 I/O 2024大會全面硬鋼OpenAI;騰訊宣布旗下的混元文生圖大模型;阿里巴巴技術下的AI自動視頻剪輯工具

? 1: 谷歌 I/O 2024 谷歌 I/O 2024 發布了眾多新技術&#xff0c;包括 Gemini AI、大語言模型和通用 AI 智能體等&#xff0c;全面顛覆搜索體驗。 谷歌 I/O 2024發布會帶來許多令人興奮的新功能和技術創新&#xff1a; Gemini 1.5 Pro&#xff1a;一個極其強大的語言模型&am…

文獻檢索神器分享:一鍵篩選頂刊論文,還能免費下載全文!

我是娜姐 迪娜學姐 &#xff0c;一個SCI醫學期刊編輯&#xff0c;探索用AI工具提效論文寫作和發表。 信息爆炸的時代&#xff0c;文獻是根本讀不完。一個關鍵詞能搜出來幾萬篇&#xff0c;而且有些結論還是完全相反的&#xff0c;到底該讀哪些&#xff1f; 第一步的文獻篩選很重…

Java面試八股之float和double的區別

Java中float和double的區別 存儲空間與精度&#xff1a; double&#xff1a;占據64位&#xff08;8字節&#xff09;存儲空間&#xff0c;屬于雙精度浮點數。它可以提供較高的精度&#xff0c;通常能夠精確表示大約15到17位十進制數字&#xff0c;適合用于需要較高精度計算或…

匯凱金業:3個高效的黃金投資技巧

黃金投資中的高效技巧往往承載了許多投資前輩的智慧與經驗教訓&#xff0c;成為新手投資者寶貴的學習資料。歷史上積累的黃金投資經驗可以作為新投資者的學習榜樣。 3個高效的黃金投資技巧 一、穩健的中長期投資策略 在金屬投資領域雖然不乏短線交易高手&#xff0c;但新手投資…

Cocos Creator 2D Mask與Layout 使用詳解

Cocos Creator是一款強大的2D游戲開發引擎&#xff0c;提供了豐富的功能和工具&#xff0c;使開發者可以輕松創建出高質量的游戲。其中&#xff0c;2D Mask和Layout是Cocos Creator中常用的兩個組件&#xff0c;它們可以幫助開發者實現更加復雜和精美的游戲界面設計。本文將詳細…