1272 摘果子(樹形dp,dfs

2021-08-15 15:34:37 字數 1105 閱讀 2431

description

樹有n個節點,樹根為1號節點,這顆果樹上有m個節點長出果實(根節點1有可能長出果實),小明要從節點1出發採集這些果實,從乙個節點爬到相鄰的另乙個節點所需要的時間為1,採集果實不需要時間,問如果要採集這m個果實,從節點1出發,並且最後需要回到節點1,最少需要多少的時間。(節點編號1到n)

input

輸入第一行為正整數n和m ( 0 <= m <= n <= 100000 ) 

接下來的n-1行每行輸入兩個數字a和b表示節點編號a和節點編號b之間有一條邊 

最後一行輸入m個數字,第i個數字v[i]表示在v[i]號節點上長有果實

output

對於每個輸入,輸出乙個數字,表示最少需要花費的時間。

4 21 2

1 32 4

2 3sample input

思路:樹形dp, 簡單說明一下把;

方便說明,假設樹是二叉樹, 其實都一樣; 

假設根結點的左子樹,右子樹都存在果子;

那麼原樹的答案是:左子樹的答案 + 2 (來回) 與 右子樹答案 + 2(來回) 的和  (最終是要回到1的);

如果某一子樹中沒果子,那這棵子樹自然不需要貢獻答案給父結點,也不用所謂來回+2了;

不斷遞迴,自然想到用dfs去實現。 結果就是從葉子節點把答案往上傳遞 。

需要注意的細節就是從某一節點,找子節點時,有可能會找到父節點,因為建樹時是雙向的(不要試圖用單向,會有bug)。

#include #include #define maxn 100005  

using namespace std;

vectore[maxn], dp(maxn), v(maxn);

int dfs(int u, int fa)

}

}

return bo;

}

int main(void)

for(int i = 0; i < m; i++)

dfs(1, -1);

cout << dp[1] << endl;

return 0;

}

收集果子(樹形dp)

題意 給你一棵樹,1為根節點,每個節點有果子數,每個節點的權值為其子樹果子的和。問多少種刪邊的方式,使得1節點的權值為k。思路 組成k的種類數?不就是多少種方法組成某個面值嗎,可以想到是樹上揹包。定義f i,j 為遞迴到第i個節點收集了j個果子的方案數。那麼有兩種子狀態 1 把 u,v 邊斷了,那麼...

nssl1196 摘果子 樹形依賴揹包,dp

有n個東西,每個東西有價值和 然後要求乙個 上限,和除了第乙個東西以外都有乙個買這個之前必須要買的東西。求最大價值 我們考慮之前的樹形揹包 然後發現時間複雜度o n 3 o n 3 o n3 之後我們考慮乙個方法 之前是將子節點合併起來所以時間會很久,可是我們可以將乙個子節點處理好,然後直接仍給它的...

C Garland (樹形DP 子樹計數問題)

又攻克一道樹形dp題,首先子樹計數問題,感覺都是先自下而上跑一遍dfs,然後根據題意然後抉擇得套路。一顆有根樹,分成三棵子樹,保證點權和相互相等。分析 子樹滿足ans 3,並且ans 3 0加入就可以了,滿足兩個點或者以上,就是行 為啥說2以上 這裡就是我得wa得點,可以所有得點值為0,你就知道了 ...