日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

蓝桥杯 - 生命之树(树形dp)

發(fā)布時(shí)間:2024/4/11 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 蓝桥杯 - 生命之树(树形dp) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

在X森林里,上帝創(chuàng)建了生命之樹。

?

他給每棵樹的每個(gè)節(jié)點(diǎn)(葉子也稱為一個(gè)節(jié)點(diǎn))上,都標(biāo)了一個(gè)整數(shù),代表這個(gè)點(diǎn)的和諧值。

上帝要在這棵樹內(nèi)選出一個(gè)非空節(jié)點(diǎn)集S,使得對(duì)于S中的任意兩個(gè)點(diǎn)a,b,都存在一個(gè)點(diǎn)列 {a, v1, v2, ..., vk, b} 使得這個(gè)點(diǎn)列中的每個(gè)點(diǎn)都是S里面的元素,且序列中相鄰兩個(gè)點(diǎn)間有一條邊相連。

?

在這個(gè)前提下,上帝要使得S中的點(diǎn)所對(duì)應(yīng)的整數(shù)的和盡量大。

這個(gè)最大的和就是上帝給生命之樹的評(píng)分。

?

經(jīng)過atm的努力,他已經(jīng)知道了上帝給每棵樹上每個(gè)節(jié)點(diǎn)上的整數(shù)。但是由于 atm 不擅長計(jì)算,他不知道怎樣有效的求評(píng)分。他需要你為他寫一個(gè)程序來計(jì)算一棵樹的分?jǐn)?shù)。

?

「輸入格式」

第一行一個(gè)整數(shù) n 表示這棵樹有 n 個(gè)節(jié)點(diǎn)。

第二行 n 個(gè)整數(shù),依次表示每個(gè)節(jié)點(diǎn)的評(píng)分。

接下來 n-1 行,每行 2 個(gè)整數(shù) u, v,表示存在一條 u 到 v 的邊。由于這是一棵樹,所以是不存在環(huán)的。

?

「輸出格式」

輸出一行一個(gè)數(shù),表示上帝給這棵樹的分?jǐn)?shù)。

?

「樣例輸入」

5

1 -2 -3 4 5

4 2

3 1

1 2

2 5

?

「樣例輸出」

8

?

「數(shù)據(jù)范圍」

對(duì)于 30% 的數(shù)據(jù),n <= 10

對(duì)于 100% 的數(shù)據(jù),0 < n <= 10^5, 每個(gè)節(jié)點(diǎn)的評(píng)分的絕對(duì)值不超過 10^6 。


題目分析:題意一開始沒讀懂,去問的zx學(xué)長,簡單來說就是從樹中求一個(gè)最大連通子塊,保證這個(gè)連通子塊的權(quán)值和最大,因?yàn)檎f子樹不太合適,就叫做連通子塊啦

題目給到了1e5的數(shù)據(jù),所以暴力是肯定不能考慮的了,因?yàn)樯婕暗綑?quán)值和的問題,所以我們不難聯(lián)想到前綴和,在樹上維護(hù)前綴和不就是樹形dp嘛,但如果是單純的維護(hù)前綴和的話,又不太好更新答案,所以我們考慮一下如何設(shè)計(jì)dp

想了半天還是沒有思路啊,但zx學(xué)長看了一眼就給秒掉了,再次不得不承認(rèn)人與人之間的差距。。

這個(gè)題目給出的是一棵無根樹,我們依然可以當(dāng)做有根樹來做,隨意找一個(gè)節(jié)點(diǎn)當(dāng)做根,跑一遍dfs,dp[i]代表節(jié)點(diǎn)i為上邊界的子連通塊的最大值,因?yàn)槭亲舆B通塊而不是子樹,所以在任意節(jié)點(diǎn)我們是可以直接斷開的,為什么要斷開呢?因?yàn)榧偃绻?jié)點(diǎn)i的某棵子樹做出的貢獻(xiàn)是負(fù)數(shù),那么我們完全可以舍棄掉這棵子樹,從而使得每次轉(zhuǎn)移的答案最優(yōu),這樣轉(zhuǎn)移方程也就很容易了:

dp[u]=max(dp[v],0);v為u的所有子節(jié)點(diǎn)

維護(hù)完dp后O(n)跑一遍最大值就是答案啦

這里需要注意一下,一開始我理解的dp[i]的含義有誤,所以導(dǎo)致整個(gè)思路混亂,從而沒有正確的設(shè)計(jì)出轉(zhuǎn)移方程,我一開始以為dp[i]代表的是到節(jié)點(diǎn)i為止,子連通塊中的最大值,從而出現(xiàn)了另一個(gè)疑問:如果最大值是在沿著節(jié)點(diǎn)i的父節(jié)點(diǎn)那條鏈上該怎么辦呢?其實(shí)并不用擔(dān)心這個(gè)問題,如果包含最大值的那一坨真的出現(xiàn)在節(jié)點(diǎn)i父節(jié)點(diǎn)的那條鏈上,雖然我們不能用節(jié)點(diǎn)i來更新最大值,但總有節(jié)點(diǎn)是可以更新到這個(gè)最大值的,我們可以這樣理解,節(jié)點(diǎn)i作為最大值這一坨的下界,自然無法更新答案,但只要是這個(gè)最大值合法,那么他必定存在一個(gè)上界,也是屬于這棵樹中的任意一個(gè)節(jié)點(diǎn),當(dāng)遍歷到上界的這個(gè)節(jié)點(diǎn)的時(shí)候,就可以更新相應(yīng)的最大值了,所以在這里個(gè)人認(rèn)為dp[i]理解為以節(jié)點(diǎn)i為上界的最大子連通塊比較合適

代碼:

#include<iostream> #include<cstdlib> #include<string> #include<cstring> #include<cstdio> #include<algorithm> #include<climits> #include<cmath> #include<cctype> #include<stack> #include<queue> #include<list> #include<vector> #include<set> #include<map> #include<sstream> #include<unordered_map> using namespace std;typedef long long LL;const int inf=0x3f3f3f3f;const int N=1e5+100;vector<int>node[N];LL dp[N];int val[N];void dfs(int u,int f) {dp[u]=val[u];for(int i=0;i<node[u].size();i++){int v=node[u][i];if(v==f)continue;dfs(v,u);dp[u]+=max(dp[v],0LL);//狀態(tài)轉(zhuǎn)移方程} }int main() { // freopen("input.txt","r",stdin); // ios::sync_with_stdio(false);int n;scanf("%d",&n);for(int i=1;i<=n;i++)scanf("%d",val+i);for(int i=1;i<n;i++){int x,y;scanf("%d%d",&x,&y);node[x].push_back(y);node[y].push_back(x);}dfs(1,-1);LL ans=-inf;for(int i=1;i<=n;i++)ans=max(ans,dp[i]);printf("%d\n",ans);return 0; }

?

總結(jié)

以上是生活随笔為你收集整理的蓝桥杯 - 生命之树(树形dp)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。