最近感覺樹形dp練習的太少了,關於此的很多姿勢還是不太會……
所以打算開始練練
description
幾乎整個byteland王國都被森林和河流所覆蓋。小點的河匯聚到一起,形成了稍大點的河。就這樣,所有的河水都匯聚並流進了一條大河,最後這條大河流進了大海。這條大河的入海口處有乙個村莊——名叫bytetown 在byteland國,有n個伐木的村莊,這些村莊都座落在河邊。目前在bytetown,有乙個巨大的伐木場,它處理著全國砍下的所有木料。木料被砍下後,順著河流而被運到bytetown的伐木場。byteland的國王決定,為了減少運輸木料的費用,再額外地建造k個伐木場。這k個伐木場將被建在其他村莊裡。這些伐木場建造後,木料就不用都被送到bytetown了,它們可以在 運輸過程中第乙個碰到的新伐木場被處理。顯然,如果伐木場座落的那個村子就不用再付運送木料的費用了。它們可以直接被本村的伐木場處理。 注意:所有的河流都不會分叉,也就是說,每乙個村子,順流而下都只有一條路——到bytetown。 國王的大臣計算出了每個村子每年要產多少木料,你的任務是決定在哪些村子建設伐木場能獲得最小的運費。其中運費的計算方法為:每一塊木料每千公尺1分錢。 編乙個程式: 1.從檔案讀入村子的個數,另外要建設的伐木場的數目,每年每個村子產的木料的塊數以及河流的描述。 2.計算最小的運費並輸出。
input
第一行 包括兩個數 n(2<=n<=100),k(1<=k<=50,且 k<=n)。n為村莊數,k為要建的伐木場的數目。除了bytetown外,每個村子依次被命名為1,2,3……n,bytetown被命名為0。 接下來n行,每行包涵3個整數 wi——每年i村子產的木料的塊數 (0<=wi<=10000) vi——離i村子下游最近的村子(或bytetown)(0<=vi<=n) di——vi到i的距離(km)。(1<=di<=10000) 保證每年所有的木料流到bytetown的運費不超過2000,000,000分 50%的資料中n不超過20。
output
輸出最小花費,精確到分。
sample input
4 2
1 0 1
1 1 10
10 2 5
1 2 3
sample output
4顯然是乙個樹形dp的問題
一開始會有乙個想法:
令f[i][j]表示在第i個點,選出j個點變成伐木場的最小運費
但是似乎並不是那麼好轉移誒……
為什麼不好轉移呢?
原因可能有2種:
1.狀態設計完全有問題
2.此狀態無法完全表示真正所有的狀態
很明顯,不好轉移的原因是2
因為題目還說要考慮到離i點最近的伐木場……
但是,我們可以發現題目中隱藏了乙個性質:
離i點最近的伐木場始終在i的上面(深度比i小且為i的祖先)
所以只要再加一維,即為:
f[i][j][k]表示在第i個點,選出j個點作為伐木場,而且離i點最近的伐木場編號為k
那麼轉移就十分的方便了
列舉每乙個兒子分多少伐木場
分兩種情況討論即可
注意邊界條件(我被邊界坑了好多次……)
兩點距離的問題可以預處理
我比較喜歡多叉樹轉成二叉樹(lc[i]表示i第乙個兒子,rc[i]表示i的第乙個兄弟),方便轉移
總時間複雜度: o(n^3*k)
1.對於dp題要能盡量看出來
2.要關注一些dp時的細節(邊界,變數等)
3.對於一種狀態難以轉移的時候,可以考慮將狀態變得更加完整或者重新想新的更好的狀態