樹形dp小結

2021-06-10 06:45:09 字數 2668 閱讀 8998

這些天做了一些樹形dp的題目,感覺有了些領悟,尤其是理解到樹形揹包就是分組揹包之後。。選出幾道不錯的總結一下

hdu 1520

hdu 4003

poj 1155

poj 2486

hdu 4313

hdu 4340

hdu 1520

入門水題

每個節點有權值,子節點和父節點不能同時選,問最後能選的最大價值是多少

dp[i][0]表示第i個節點不選,dp[i][1]表示第i個節點擊

dp[i][0] = sum(max(dp[j][1],dp[j][0]))

dp[i][1] = sum(dp[j][0]) + w[i]

hdu 2196

求樹每個點到其他點的最遠距離

兩次dfs,**分別是子節點和父節點

第一次,把樹變為有根樹,fir[i],sec[i],表示第i個點到葉子節點的最長距離和次長距離

第二次,考慮**可以是父節點,再次跟新fir,sec

hdu 4003

一棵有權樹,從根結點中放入k個機械人,求用這k個機械人遍歷所有的結點最少的權值和 

這題確實是個好題

剛開始很容易想到dp[i][j]表示用j個機械人遍歷第i個節點為根的子樹的最小花費。

然後父節點的狀態由子節點更新,每個子節點下子樹的機械人是可以是0-j,這就是乙個分組揹包的過程~。其中難點是看出乙個性質,就是如果如果最終的狀態中以i為根結點的樹中有j(j>0)個機械人,那麼不可能有別的機械人到了這棵子樹後又跑到別的樹中去,因為那樣的話,一定會比j中的某乙個到達i後跑與其相同的路徑再回到i,再接著跑它的路徑要差(多了一條i回去的邊).所以每棵子樹只有兩種策略。1.由乙個機械人遍歷子樹然後返回。2.k個機械人遍歷,而且不返回。

void tree_dp(int u,int fa)

}dp[u][0] += dp[v][0] + 2*w;

}}

poj 1155

最基礎的樹形揹包。但是寫的好搓。。

dp[u][j] 節點u,傳送j個客戶,最大收益

void tree_dp(int u,int fa)

} if(isleaf)

}

poj 2486

很不錯的樹形揹包模型

給定一棵節點數為n的樹,每個節點都放有一些蘋果,現在從根節點1開始走,每走一條邊算一步,每經過乙個節點就能吃掉這個節點的蘋果(吃掉就沒了),問走m步最多能吃幾個蘋果?

這題特殊的地方在於,可以回到根節點也可以不會到根節點。

//最終回到根節點

dp[u][j][0] = max(dp[u][j][0],dp[u][j-2-k][0] + dp[v][k][0]);

//從前面的兄弟節點回到根節點,然後到此子節點不會到根節點

dp[u][j][1] = max(dp[u][j][1],dp[u][j-1-k][0] + dp[v][k][1]);

//從此子節點回到根節點,但是會在後面的兄弟節點下去不會來

dp[u][j][1] = max(dp[u][j][1],dp[u][j-2-k][1] + dp[v][k][0]);

hdu 4313 matrix 樹形dp

對一顆節點數為n的樹,所有節點分為,危險點和安全點兩種。每條邊都有邊權,現在要求刪掉一些邊,把這顆樹分成k棵子數,且保證每個子數中最多包含一危險點,問刪掉的邊的最小邊權總和。

首先可以看出兩個無需決策的選擇。

1.如果根節點是危險點,那麼其子樹中就不能有危險點。

2.如果根節點點是安全點,且其子樹中有危險點,則其必須要連乙個危險點。

然後,我們要選擇的只是當2中子孫節點中有多個危險點是,我們該選那乙個。

顯然對於一顆數,只有乙個危險點,對於其中每乙個節點,要麼危險點和自己的關係有三種

dp[u][1] 表示當前節點為u,危險點在子孫節點,或是自己

dp[u][0] 表示當前節點為u,危險點在父節點中

狀態表示好了,不難得出轉移方程。

當u是危險點時 

dp[u][0] = inf;

dp[u][1] = sum(min(dp[s][1]+w[u][s],dp[s][0]))

當u是安全點時

dp[u][0] = sum(min(dp[s][1]+w[u][s],dp[s][0])) //子節點這中不會有危險點。

dp[u][1] = min(dp[u][0] - min(dp[s][1]+w[u][s]) + dp[s][1])

hdu 4340 capturing a country 樹形dp

這題解法和hdu 4313類似

對樹中每個節點來說,其所在染色集的完整費用點要麼在它上面,要麼是它或其子孫節點,即三種**

dp[i][j][0] 表示第i個點染j色且完整費用點在其上面

dp[i][j][1] 表示第i個點染j色且完整費用點是其本身或其其子孫節點

* s = sum(min(dp[s][j][0],dp[s][1-j][1]))

* dp[i][j][0] = cost[i][j]/2 + s; 

* dp[i][j][1] = min(cost[i][j]+s,cost[i][j]/2 + min(dp[s][j][1]-min(dp[s][j][0],dp[s][1-j][1]));

樹形dp小結 2

樹形dp的題一般都結合著揹包來用。以下的幾道題都是結合著揹包的思想來的 1 樹形dp 分組揹包 狀態比較難想 之前說過在最長距離的那道題裡說過,不會返回。但是有的提示需要考慮返回的節點的。下面就是乙個例子 題目大意 給你乙個蘋果樹,有n個節點,每個節點上都有乙個乙個蘋果也就有乙個權值,當你經過這個點...

樹形DP 樹形DP四例

是時候練一下dp了!我的題單 portkey f u,if fu,i 表示以u uu為根節點的子樹中保留i ii條樹枝的最大蘋果數 f u,i max f max f fu,i max這些題是菜,但也不能輕視啊!include using namespace std define in read i...

HLOJ 樹形DP前置 DFS(樹形DP入門)

給定一棵 n nn 個點的樹,根為 t tt求每個點的父親是哪個點,t tt 的父親輸出 0 00第一行兩個整數 n,t n,tn,t接下來 n 1 n 1n 1 行,每行兩個整數 x,y x,yx,y,表示 x,y x,yx,y 之間有一條邊 n nn 行,第 i ii 行乙個整數,表示 i ii...