這些天做了一些樹形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...